@dacostafilipe/react-geoportail 0.1.6 → 0.1.7

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.
@@ -56,3 +56,4 @@ export interface GeoportailMapHandle {
56
56
  * or imperatively control the view.
57
57
  */
58
58
  export declare const GeoportailMap: React.ForwardRefExoticComponent<GeoportailMapProps & React.RefAttributes<GeoportailMapHandle>>;
59
+ export declare function convertMapClickCoordinateToLatLon(map: LuxMapInstance, coordinate: [number, number]): LatLon;
@@ -0,0 +1 @@
1
+ export {};
@@ -1,13 +1,13 @@
1
- import { jsx as T, jsxs as z } from "react/jsx-runtime";
2
- import { useState as F, useEffect as S, forwardRef as et, useRef as R, useImperativeHandle as ot, useCallback as I } from "react";
3
- const st = "https://apiv3.geoportail.lu/", rt = "https", at = "https://apiv3.geoportail.lu/static-ngeo/build/fr.json", ct = "https://apiv3.geoportail.lu/static-ngeo/build/apiv3.css", it = "https://apiv3.geoportail.lu/static-ngeo/build/vendor.js", lt = "https://apiv3.geoportail.lu/static-ngeo/build/apiv3.js", ut = "geoportail-apiv3-css", dt = "geoportail-apiv3-vendor", ft = "geoportail-apiv3-script", _ = "data-geoportail-status";
4
- let A = null;
5
- function ht() {
6
- return A || (typeof window > "u" || typeof document > "u" ? Promise.reject(new Error("loadLuxApi must be called in a browser environment")) : (A = gt().catch((n) => {
7
- throw A = null, n instanceof Error ? n : new Error(String(n));
8
- }), A));
1
+ import { jsx as y, jsxs as W } from "react/jsx-runtime";
2
+ import { useState as j, useEffect as T, forwardRef as tt, useRef as R, useImperativeHandle as nt, useCallback as C } from "react";
3
+ const ot = "https://apiv3.geoportail.lu/", et = "https", st = "https://apiv3.geoportail.lu/static-ngeo/build/fr.json", rt = "https://apiv3.geoportail.lu/static-ngeo/build/apiv3.css", ct = "https://apiv3.geoportail.lu/static-ngeo/build/vendor.js", at = "https://apiv3.geoportail.lu/static-ngeo/build/apiv3.js", it = "geoportail-apiv3-css", lt = "geoportail-apiv3-vendor", ut = "geoportail-apiv3-script", A = "data-geoportail-status";
4
+ let S = null;
5
+ function dt() {
6
+ return S || (typeof window > "u" || typeof document > "u" ? Promise.reject(new Error("loadLuxApi must be called in a browser environment")) : (S = ht().catch((n) => {
7
+ throw S = null, n instanceof Error ? n : new Error(String(n));
8
+ }), S));
9
9
  }
10
- function pt(n, e) {
10
+ function ft(n, o) {
11
11
  let i = 0;
12
12
  const s = () => {
13
13
  if (window.lux) {
@@ -15,174 +15,174 @@ function pt(n, e) {
15
15
  return;
16
16
  }
17
17
  if (i++ >= 100) {
18
- A = null, e(new Error("Timed out waiting for window.lux to be defined"));
18
+ S = null, o(new Error("Timed out waiting for window.lux to be defined"));
19
19
  return;
20
20
  }
21
21
  setTimeout(s, 50);
22
22
  };
23
23
  s();
24
24
  }
25
- async function gt() {
25
+ async function ht() {
26
26
  if (window.lux) {
27
- W(window.lux);
27
+ z(window.lux);
28
28
  return;
29
29
  }
30
- await Lt(ut, ct), await V(dt, it), await V(ft, lt), await wt(), W(window.lux);
30
+ await gt(it, rt), await V(lt, ct), await V(ut, at), await pt(), z(window.lux);
31
31
  }
32
- function wt() {
33
- return new Promise((n, e) => {
34
- pt(n, e);
32
+ function pt() {
33
+ return new Promise((n, o) => {
34
+ ft(n, o);
35
35
  });
36
36
  }
37
- function W(n) {
38
- n.setBaseUrl(st, rt), n.setI18nUrl(at);
37
+ function z(n) {
38
+ n.setBaseUrl(ot, et), n.setI18nUrl(st);
39
39
  }
40
- function V(n, e) {
41
- const o = document.getElementById(n);
42
- return o ? Y(o, e, "script") : new Promise((i, s) => {
40
+ function V(n, o) {
41
+ const e = document.getElementById(n);
42
+ return e ? Y(e, o, "script") : new Promise((i, s) => {
43
43
  const t = document.createElement("script");
44
- t.id = n, t.src = e, t.async = !1, t.setAttribute(_, "loading"), X(
44
+ t.id = n, t.src = o, t.async = !1, t.setAttribute(A, "loading"), F(
45
45
  t,
46
46
  () => i(),
47
- () => s(new Error(`Failed to load Geoportail script from ${e}`)),
47
+ () => s(new Error(`Failed to load Geoportail script from ${o}`)),
48
48
  "script"
49
49
  ), document.head.appendChild(t);
50
50
  });
51
51
  }
52
- function Lt(n, e) {
53
- const o = document.getElementById(n);
54
- return o ? Y(o, e, "stylesheet") : new Promise((i, s) => {
52
+ function gt(n, o) {
53
+ const e = document.getElementById(n);
54
+ return e ? Y(e, o, "stylesheet") : new Promise((i, s) => {
55
55
  const t = document.createElement("link");
56
- t.id = n, t.rel = "stylesheet", t.href = e, t.setAttribute(_, "loading"), X(
56
+ t.id = n, t.rel = "stylesheet", t.href = o, t.setAttribute(A, "loading"), F(
57
57
  t,
58
58
  () => i(),
59
- () => s(new Error(`Failed to load Geoportail stylesheet from ${e}`)),
59
+ () => s(new Error(`Failed to load Geoportail stylesheet from ${o}`)),
60
60
  "stylesheet"
61
61
  ), document.head.appendChild(t);
62
62
  });
63
63
  }
64
- function Y(n, e, o) {
65
- const i = n.getAttribute(_);
66
- return i === "loaded" ? Promise.resolve() : i === "error" ? (n.remove(), Promise.reject(new Error(`Failed to load Geoportail ${o} from ${e}`))) : new Promise((s, t) => {
67
- X(
64
+ function Y(n, o, e) {
65
+ const i = n.getAttribute(A);
66
+ return i === "loaded" ? Promise.resolve() : i === "error" ? (n.remove(), Promise.reject(new Error(`Failed to load Geoportail ${e} from ${o}`))) : new Promise((s, t) => {
67
+ F(
68
68
  n,
69
69
  () => s(),
70
- () => t(new Error(`Failed to load Geoportail ${o} from ${e}`)),
71
- o
70
+ () => t(new Error(`Failed to load Geoportail ${e} from ${o}`)),
71
+ e
72
72
  );
73
73
  });
74
74
  }
75
- function X(n, e, o, i) {
75
+ function F(n, o, e, i) {
76
76
  const s = () => {
77
- n.setAttribute(_, "loaded"), f(), e();
77
+ n.setAttribute(A, "loaded"), h(), o();
78
78
  }, t = () => {
79
- n.setAttribute(_, "error"), f(), n.remove(), o();
80
- }, f = () => {
79
+ n.setAttribute(A, "error"), h(), n.remove(), e();
80
+ }, h = () => {
81
81
  n.removeEventListener("load", s), n.removeEventListener("error", t);
82
82
  };
83
- return n.addEventListener("load", s, { once: !0 }), n.addEventListener("error", t, { once: !0 }), i === "stylesheet" ? n.sheet && s() : n.dataset.geoportailStatus === "loaded" && s(), f;
83
+ return n.addEventListener("load", s, { once: !0 }), n.addEventListener("error", t, { once: !0 }), i === "stylesheet" ? n.sheet && s() : n.dataset.geoportailStatus === "loaded" && s(), h;
84
84
  }
85
- function Et() {
86
- const [n, e] = F({
85
+ function wt() {
86
+ const [n, o] = j({
87
87
  status: "loading",
88
88
  lux: null,
89
89
  error: null
90
90
  });
91
- return S(() => {
92
- let o = !1;
93
- return ht().then(() => {
94
- o || e({ status: "ready", lux: window.lux, error: null });
91
+ return T(() => {
92
+ let e = !1;
93
+ return dt().then(() => {
94
+ e || o({ status: "ready", lux: window.lux, error: null });
95
95
  }).catch((i) => {
96
- o || e({
96
+ e || o({
97
97
  status: "error",
98
98
  lux: null,
99
99
  error: i instanceof Error ? i : new Error(String(i))
100
100
  });
101
101
  }), () => {
102
- o = !0;
102
+ e = !0;
103
103
  };
104
104
  }, []), n;
105
105
  }
106
- const k = 8e4, Z = 1e5, q = 6.16666666666667, J = 49.8333333333333, U = 1, v = 6378388, j = 1 / 297, O = v * (1 - j), E = 1 - O * O / (v * v), C = -87, D = -98, K = -121;
106
+ const k = 8e4, Z = 1e5, q = 6.16666666666667, J = 49.8333333333333, I = 1, v = 6378388, N = 1 / 297, D = v * (1 - N), E = 1 - D * D / (v * v), U = -87, P = -98, K = -121;
107
107
  function M(n) {
108
108
  return n * Math.PI / 180;
109
109
  }
110
- function y(n) {
110
+ function _(n) {
111
111
  return n * 180 / Math.PI;
112
112
  }
113
- function mt(n, e) {
114
- const o = M(n), i = M(e), s = Math.sin(o), t = Math.cos(o), f = Math.sin(i), h = Math.cos(i), r = 6378137, c = 1 / 298.257223563, p = r * (1 - c), l = 1 - p * p / (r * r), d = v - r, a = j - c, g = r / Math.sqrt(1 - l * s * s), w = 1 / (r * (1 - l) / Math.pow(1 - l * s * s, 1.5)) * (g * (l / (1 - l)) * s * t * (d / r) + (g / r + 1) * s * t * a * (r / p) - (C * s * h + D * s * f - K * t)), L = 1 / (g * t) * (-C * f + D * h);
113
+ function Lt(n, o) {
114
+ const e = M(n), i = M(o), s = Math.sin(e), t = Math.cos(e), h = Math.sin(i), p = Math.cos(i), r = 6378137, c = 1 / 298.257223563, f = r * (1 - c), l = 1 - f * f / (r * r), d = v - r, a = N - c, g = r / Math.sqrt(1 - l * s * s), w = 1 / (r * (1 - l) / Math.pow(1 - l * s * s, 1.5)) * (g * (l / (1 - l)) * s * t * (d / r) + (g / r + 1) * s * t * a * (r / f) - (U * s * p + P * s * h - K * t)), L = 1 / (g * t) * (-U * h + P * p);
115
115
  return {
116
- lat: n + y(w),
117
- lon: e + y(L)
116
+ lat: n + _(w),
117
+ lon: o + _(L)
118
118
  };
119
119
  }
120
- function vt(n, e) {
121
- const o = M(n), i = M(e), s = Math.sin(o), t = Math.cos(o), f = Math.sin(i), h = Math.cos(i), r = v / Math.sqrt(1 - E * s * s), c = v * (1 - E) / Math.pow(1 - E * s * s, 1.5), p = 6378137 - v, d = 1 / 298.257223563 - j, a = 1 / c * (r * (E / (1 - E)) * s * t * (p / v) + (r / v + 1) * s * t * d * (v / O) + (C * s * h + D * s * f - K * t)), g = 1 / (r * t) * (C * f - D * h);
120
+ function Et(n, o) {
121
+ const e = M(n), i = M(o), s = Math.sin(e), t = Math.cos(e), h = Math.sin(i), p = Math.cos(i), r = v / Math.sqrt(1 - E * s * s), c = v * (1 - E) / Math.pow(1 - E * s * s, 1.5), f = 6378137 - v, d = 1 / 298.257223563 - N, a = 1 / c * (r * (E / (1 - E)) * s * t * (f / v) + (r / v + 1) * s * t * d * (v / D) + (U * s * p + P * s * h - K * t)), g = 1 / (r * t) * (U * h - P * p);
122
122
  return {
123
- lat: n + y(a),
124
- lon: e + y(g)
123
+ lat: n + _(a),
124
+ lon: o + _(g)
125
125
  };
126
126
  }
127
- function Mt(n, e) {
128
- const o = M(n), i = M(e), s = M(q), t = M(J), f = Math.sin(o), h = Math.cos(o), r = Math.tan(o), c = v / Math.sqrt(1 - E * f * f), p = r * r, l = E / (1 - E) * h * h, d = i - s, a = h * d, g = G(o), m = G(t), w = k + U * c * (a + a * a * a * (1 - p + l) / 6 + a * a * a * a * a * (5 - 18 * p + p * p + 72 * l) / 120), L = Z + U * (g - m + c * r * (a * a / 2 + a * a * a * a * (5 - p + 9 * l + 4 * l * l) / 24 + a * a * a * a * a * a * (61 - 58 * p + p * p + 600 * l) / 720));
127
+ function mt(n, o) {
128
+ const e = M(n), i = M(o), s = M(q), t = M(J), h = Math.sin(e), p = Math.cos(e), r = Math.tan(e), c = v / Math.sqrt(1 - E * h * h), f = r * r, l = E / (1 - E) * p * p, d = i - s, a = p * d, g = G(e), m = G(t), w = k + I * c * (a + a * a * a * (1 - f + l) / 6 + a * a * a * a * a * (5 - 18 * f + f * f + 72 * l) / 120), L = Z + I * (g - m + c * r * (a * a / 2 + a * a * a * a * (5 - f + 9 * l + 4 * l * l) / 24 + a * a * a * a * a * a * (61 - 58 * f + f * f + 600 * l) / 720));
129
129
  return { easting: w, northing: L };
130
130
  }
131
- function xt(n, e) {
132
- const o = n - k, i = e - Z, s = M(J), t = M(q), r = (G(s) + i / U) / (v * (1 - E / 4 - 3 * E * E / 64)), c = (1 - Math.sqrt(1 - E)) / (1 + Math.sqrt(1 - E)), p = r + (3 * c / 2 - 27 * c * c * c / 32) * Math.sin(2 * r) + (21 * c * c / 16 - 55 * c * c * c * c / 32) * Math.sin(4 * r) + 151 * c * c * c / 96 * Math.sin(6 * r), l = Math.sin(p), d = Math.cos(p), a = Math.tan(p), g = v / Math.sqrt(1 - E * l * l), m = a * a, w = E / (1 - E) * d * d, L = v * (1 - E) / Math.pow(1 - E * l * l, 1.5), u = o / (g * U), x = p - g * a / L * (u * u / 2 - u * u * u * u * (5 + 3 * m + 10 * w - 4 * w * w) / 24 + u * u * u * u * u * u * (61 + 90 * m + 298 * w + 45 * m * m) / 720), b = t + (u - u * u * u * (1 + 2 * m + w) / 6 + u * u * u * u * u * (5 - 2 * w + 28 * m - 3 * w * w) / 120) / d;
133
- return { lat: y(x), lon: y(b) };
131
+ function vt(n, o) {
132
+ const e = n - k, i = o - Z, s = M(J), t = M(q), r = (G(s) + i / I) / (v * (1 - E / 4 - 3 * E * E / 64)), c = (1 - Math.sqrt(1 - E)) / (1 + Math.sqrt(1 - E)), f = r + (3 * c / 2 - 27 * c * c * c / 32) * Math.sin(2 * r) + (21 * c * c / 16 - 55 * c * c * c * c / 32) * Math.sin(4 * r) + 151 * c * c * c / 96 * Math.sin(6 * r), l = Math.sin(f), d = Math.cos(f), a = Math.tan(f), g = v / Math.sqrt(1 - E * l * l), m = a * a, w = E / (1 - E) * d * d, L = v * (1 - E) / Math.pow(1 - E * l * l, 1.5), u = e / (g * I), x = f - g * a / L * (u * u / 2 - u * u * u * u * (5 + 3 * m + 10 * w - 4 * w * w) / 24 + u * u * u * u * u * u * (61 + 90 * m + 298 * w + 45 * m * m) / 720), b = t + (u - u * u * u * (1 + 2 * m + w) / 6 + u * u * u * u * u * (5 - 2 * w + 28 * m - 3 * w * w) / 120) / d;
133
+ return { lat: _(x), lon: _(b) };
134
134
  }
135
135
  function G(n) {
136
- const e = E, o = e * e, i = o * e;
137
- return v * ((1 - e / 4 - 3 * o / 64 - 5 * i / 256) * n - (3 * e / 8 + 3 * o / 32 + 45 * i / 1024) * Math.sin(2 * n) + (15 * o / 256 + 45 * i / 1024) * Math.sin(4 * n) - 35 * i / 3072 * Math.sin(6 * n));
136
+ const o = E, e = o * o, i = e * o;
137
+ return v * ((1 - o / 4 - 3 * e / 64 - 5 * i / 256) * n - (3 * o / 8 + 3 * e / 32 + 45 * i / 1024) * Math.sin(2 * n) + (15 * e / 256 + 45 * i / 1024) * Math.sin(4 * n) - 35 * i / 3072 * Math.sin(6 * n));
138
138
  }
139
- function P(n, e) {
140
- const o = mt(n, e);
141
- return Mt(o.lat, o.lon);
139
+ function O(n, o) {
140
+ const e = Lt(n, o);
141
+ return mt(e.lat, e.lon);
142
142
  }
143
- function Q(n, e) {
144
- const o = xt(n, e);
145
- return vt(o.lat, o.lon);
143
+ function Q(n, o) {
144
+ const e = vt(n, o);
145
+ return Et(e.lat, e.lon);
146
146
  }
147
- const bt = { lat: 49.6116, lon: 6.1319 }, Rt = "basemap_2015_global", Ut = et(
147
+ const Mt = "EPSG:3857", xt = "EPSG:4326", bt = { lat: 49.6116, lon: 6.1319 }, Rt = "basemap_2015_global", Ut = tt(
148
148
  function({
149
- center: e = bt,
150
- zoom: o = 12,
149
+ center: o = bt,
150
+ zoom: e = 12,
151
151
  bgLayer: i = Rt,
152
152
  markerMode: s = "none",
153
153
  markerPosition: t,
154
- onMarkerPlace: f,
155
- className: h,
154
+ onMarkerPlace: h,
155
+ className: p,
156
156
  style: r,
157
157
  layers: c
158
- }, p) {
159
- const l = Et(), d = R(null), a = R(null), g = R(null), m = R(null), w = R(f);
160
- return w.current = f, S(() => {
158
+ }, f) {
159
+ const l = wt(), d = R(null), a = R(null), g = R(null), m = R(null), w = R(h);
160
+ return w.current = h, T(() => {
161
161
  if (l.status !== "ready" || !d.current) return;
162
- const L = l.lux, { easting: u, northing: x } = P(e.lat, e.lon), b = new L.Map({
162
+ const L = l.lux, { easting: u, northing: x } = O(o.lat, o.lon), b = new L.Map({
163
163
  target: d.current,
164
164
  bgLayer: i,
165
- zoom: o,
165
+ zoom: e,
166
166
  position: [u, x],
167
167
  ...c && c.length > 0 ? { layers: c, layerOpacities: c.map(() => 1) } : {}
168
168
  });
169
169
  return a.current = b, () => {
170
170
  a.current = null, g.current = null, m.current = null;
171
171
  };
172
- }, [l.status]), S(() => {
172
+ }, [l.status]), T(() => {
173
173
  const L = a.current;
174
174
  if (!L || l.status !== "ready") return;
175
175
  if (m.current && (L.un("singleclick", m.current), m.current = null), s === "none") {
176
- At(L, g);
176
+ St(L, g);
177
177
  return;
178
178
  }
179
- const u = t ?? (s === "fixed" ? e : void 0);
179
+ const u = t ?? (s === "fixed" ? o : void 0);
180
180
  if (u && H(L, u, g), s === "click") {
181
181
  const x = (...b) => {
182
182
  var B;
183
- const N = b[0];
184
- if (!N.coordinate) return;
185
- const [tt, nt] = N.coordinate, $ = Q(tt, nt);
183
+ const X = b[0];
184
+ if (!X.coordinate) return;
185
+ const $ = Tt(L, X.coordinate);
186
186
  H(L, $, g), (B = w.current) == null || B.call(w, $);
187
187
  };
188
188
  m.current = x, L.on("singleclick", x);
@@ -192,32 +192,32 @@ const bt = { lat: 49.6116, lon: 6.1319 }, Rt = "basemap_2015_global", Ut = et(
192
192
  s,
193
193
  t == null ? void 0 : t.lat,
194
194
  t == null ? void 0 : t.lon,
195
- e.lat,
196
- e.lon
197
- ]), ot(p, () => ({
195
+ o.lat,
196
+ o.lon
197
+ ]), nt(f, () => ({
198
198
  getLuxMap: () => a.current,
199
199
  setCenter(L) {
200
200
  const u = a.current;
201
201
  if (!u) return;
202
- const { easting: x, northing: b } = P(L.lat, L.lon);
202
+ const { easting: x, northing: b } = O(L.lat, L.lon);
203
203
  u.getView().setCenter([x, b]);
204
204
  },
205
205
  setZoom(L) {
206
206
  var u;
207
207
  (u = a.current) == null || u.getView().setZoom(L);
208
208
  }
209
- })), l.status === "error" ? /* @__PURE__ */ T(
209
+ })), l.status === "error" ? /* @__PURE__ */ y(
210
210
  "div",
211
211
  {
212
- className: h,
212
+ className: p,
213
213
  style: { display: "flex", alignItems: "center", justifyContent: "center", background: "#f5f5f5", ...r },
214
- children: /* @__PURE__ */ z("span", { style: { color: "#c00" }, children: [
214
+ children: /* @__PURE__ */ W("span", { style: { color: "#c00" }, children: [
215
215
  "Failed to load Geoportail API: ",
216
216
  l.error.message
217
217
  ] })
218
218
  }
219
- ) : /* @__PURE__ */ z("div", { style: { position: "relative", ...r }, className: h, children: [
220
- l.status === "loading" && /* @__PURE__ */ T(
219
+ ) : /* @__PURE__ */ W("div", { style: { position: "relative", ...r }, className: p, children: [
220
+ l.status === "loading" && /* @__PURE__ */ y(
221
221
  "div",
222
222
  {
223
223
  style: {
@@ -229,10 +229,10 @@ const bt = { lat: 49.6116, lon: 6.1319 }, Rt = "basemap_2015_global", Ut = et(
229
229
  background: "rgba(255,255,255,0.7)",
230
230
  zIndex: 10
231
231
  },
232
- children: /* @__PURE__ */ T("span", { children: "Loading map…" })
232
+ children: /* @__PURE__ */ y("span", { children: "Loading map…" })
233
233
  }
234
234
  ),
235
- /* @__PURE__ */ T(
235
+ /* @__PURE__ */ y(
236
236
  "div",
237
237
  {
238
238
  ref: d,
@@ -242,56 +242,67 @@ const bt = { lat: 49.6116, lon: 6.1319 }, Rt = "basemap_2015_global", Ut = et(
242
242
  ] });
243
243
  }
244
244
  );
245
- function H(n, e, o) {
245
+ function H(n, o, e) {
246
246
  const i = window.ol;
247
247
  if (!i) return;
248
- const { easting: s, northing: t } = P(e.lat, e.lon);
249
- if (o.current) {
250
- o.current.setPosition([s, t]);
248
+ const { easting: s, northing: t } = O(o.lat, o.lon);
249
+ if (e.current) {
250
+ e.current.setPosition([s, t]);
251
251
  return;
252
252
  }
253
- const f = document.createElement("div");
254
- f.innerHTML = yt, f.style.cssText = "cursor:pointer;transform:translate(-50%,-100%);line-height:0;";
255
- const h = new i.Overlay({
256
- element: f,
253
+ const h = document.createElement("div");
254
+ h.innerHTML = _t, h.style.cssText = "cursor:pointer;transform:translate(-50%,-100%);line-height:0;";
255
+ const p = new i.Overlay({
256
+ element: h,
257
257
  positioning: "bottom-center",
258
258
  stopEvent: !1
259
259
  });
260
- h.setPosition([s, t]), n.addOverlay(h), o.current = h;
260
+ p.setPosition([s, t]), n.addOverlay(p), e.current = p;
261
261
  }
262
- function At(n, e) {
263
- !e.current || !window.ol || (e.current.setPosition(void 0), e.current = null);
262
+ function St(n, o) {
263
+ !o.current || !window.ol || (o.current.setPosition(void 0), o.current = null);
264
264
  }
265
- const yt = `<svg xmlns="http://www.w3.org/2000/svg" width="30" height="40" viewBox="0 0 30 40">
265
+ const _t = `<svg xmlns="http://www.w3.org/2000/svg" width="30" height="40" viewBox="0 0 30 40">
266
266
  <path d="M15 0C7.268 0 1 6.268 1 14c0 10.5 14 26 14 26S29 24.5 29 14C29 6.268 22.732 0 15 0z"
267
267
  fill="#e53935" stroke="#b71c1c" stroke-width="1.5"/>
268
268
  <circle cx="15" cy="14" r="5" fill="white"/>
269
- </svg>`, St = "https://api.geoportail.lu/geocoder/reverseGeocode";
270
- function Ct() {
271
- const [n, e] = F({
269
+ </svg>`;
270
+ function Tt(n, o) {
271
+ var p, r, c, f, l;
272
+ const e = window.ol, i = (p = e == null ? void 0 : e.proj) == null ? void 0 : p.transform;
273
+ if (!i) {
274
+ const [d, a] = o;
275
+ return Q(d, a);
276
+ }
277
+ const s = ((l = (f = (c = (r = n.getView()).getProjection) == null ? void 0 : c.call(r)) == null ? void 0 : f.getCode) == null ? void 0 : l.call(f)) ?? Mt, [t, h] = i(o, s, xt);
278
+ return { lat: h, lon: t };
279
+ }
280
+ const At = "https://api.geoportail.lu/geocoder/reverseGeocode";
281
+ function Pt() {
282
+ const [n, o] = j({
272
283
  status: "idle",
273
284
  address: null,
274
285
  error: null
275
- }), o = R(null);
276
- S(() => () => {
286
+ }), e = R(null);
287
+ T(() => () => {
277
288
  var t;
278
- (t = o.current) == null || t.abort();
289
+ (t = e.current) == null || t.abort();
279
290
  }, []);
280
- const i = I(async (t) => {
281
- var h, r;
282
- (h = o.current) == null || h.abort();
283
- const f = new AbortController();
284
- o.current = f, e({ status: "loading", address: null, error: null });
291
+ const i = C(async (t) => {
292
+ var p, r;
293
+ (p = e.current) == null || p.abort();
294
+ const h = new AbortController();
295
+ e.current = h, o({ status: "loading", address: null, error: null });
285
296
  try {
286
- const { easting: c, northing: p } = P(t.lat, t.lon), l = new URL(St);
287
- l.searchParams.set("easting", String(c)), l.searchParams.set("northing", String(p));
288
- const d = await fetch(l.toString(), { signal: f.signal });
297
+ const { easting: c, northing: f } = O(t.lat, t.lon), l = new URL(At);
298
+ l.searchParams.set("easting", String(c)), l.searchParams.set("northing", String(f));
299
+ const d = await fetch(l.toString(), { signal: h.signal });
289
300
  if (!d.ok)
290
301
  throw new Error(`Reverse geocode request failed: ${d.status} ${d.statusText}`);
291
302
  const g = (r = (await d.json()).results) == null ? void 0 : r[0];
292
303
  if (!g)
293
304
  throw new Error("No results returned for this position");
294
- e({
305
+ o({
295
306
  status: "success",
296
307
  address: {
297
308
  label: g.name ?? "",
@@ -303,38 +314,38 @@ function Ct() {
303
314
  });
304
315
  } catch (c) {
305
316
  if (c instanceof DOMException && c.name === "AbortError") return;
306
- e({
317
+ o({
307
318
  status: "error",
308
319
  address: null,
309
320
  error: c instanceof Error ? c : new Error(String(c))
310
321
  });
311
322
  }
312
- }, []), s = I(() => {
323
+ }, []), s = C(() => {
313
324
  var t;
314
- (t = o.current) == null || t.abort(), e({ status: "idle", address: null, error: null });
325
+ (t = e.current) == null || t.abort(), o({ status: "idle", address: null, error: null });
315
326
  }, []);
316
327
  return { state: n, lookup: i, reset: s };
317
328
  }
318
- const _t = "https://apiv3.geoportail.lu/geocode/search";
319
- function Dt() {
320
- const [n, e] = F({
329
+ const yt = "https://apiv3.geoportail.lu/geocode/search";
330
+ function Ot() {
331
+ const [n, o] = j({
321
332
  status: "idle",
322
333
  results: null,
323
334
  error: null
324
- }), o = R(null);
325
- S(() => () => {
335
+ }), e = R(null);
336
+ T(() => () => {
326
337
  var t;
327
- (t = o.current) == null || t.abort();
338
+ (t = e.current) == null || t.abort();
328
339
  }, []);
329
- const i = I(async (t) => {
330
- var h;
331
- (h = o.current) == null || h.abort();
332
- const f = new AbortController();
333
- o.current = f, e({ status: "loading", results: null, error: null });
340
+ const i = C(async (t) => {
341
+ var p;
342
+ (p = e.current) == null || p.abort();
343
+ const h = new AbortController();
344
+ e.current = h, o({ status: "loading", results: null, error: null });
334
345
  try {
335
- const r = new URL(_t);
346
+ const r = new URL(yt);
336
347
  t.queryString ? r.searchParams.set("queryString", t.queryString) : (t.num && r.searchParams.set("num", t.num), t.street && r.searchParams.set("street", t.street), t.zip && r.searchParams.set("zip", t.zip), t.locality && r.searchParams.set("locality", t.locality));
337
- const c = await fetch(r.toString(), { signal: f.signal });
348
+ const c = await fetch(r.toString(), { signal: h.signal });
338
349
  if (!c.ok)
339
350
  throw new Error(`Geocode request failed: ${c.status} ${c.statusText}`);
340
351
  const l = ((await c.json()).results ?? []).map((d) => {
@@ -350,28 +361,28 @@ function Dt() {
350
361
  locality: (w = d.AddressDetails) == null ? void 0 : w.locality
351
362
  };
352
363
  });
353
- e({ status: "success", results: l, error: null });
364
+ o({ status: "success", results: l, error: null });
354
365
  } catch (r) {
355
366
  if (r instanceof DOMException && r.name === "AbortError") return;
356
- e({
367
+ o({
357
368
  status: "error",
358
369
  results: null,
359
370
  error: r instanceof Error ? r : new Error(String(r))
360
371
  });
361
372
  }
362
- }, []), s = I(() => {
373
+ }, []), s = C(() => {
363
374
  var t;
364
- (t = o.current) == null || t.abort(), e({ status: "idle", results: null, error: null });
375
+ (t = e.current) == null || t.abort(), o({ status: "idle", results: null, error: null });
365
376
  }, []);
366
377
  return { state: n, search: i, reset: s };
367
378
  }
368
379
  export {
369
380
  Ut as GeoportailMap,
370
- P as latLonToLuref,
371
- ht as loadLuxApi,
381
+ O as latLonToLuref,
382
+ dt as loadLuxApi,
372
383
  Q as lurefToLatLon,
373
- Dt as useGeocode,
374
- Et as useLuxApi,
375
- Ct as useReverseGeocode
384
+ Ot as useGeocode,
385
+ wt as useLuxApi,
386
+ Pt as useReverseGeocode
376
387
  };
377
388
  //# sourceMappingURL=react-geoportail.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"react-geoportail.js","sources":["../src/utils/loader.ts","../src/hooks/useLuxApi.ts","../src/utils/coordinates.ts","../src/components/GeoportailMap.tsx","../src/hooks/useReverseGeocode.ts","../src/hooks/useGeocode.ts"],"sourcesContent":["/**\n * Dynamically injects the Geoportail v3 assets and resolves when\n * the global `lux` namespace is available.\n */\n\nconst LUX_BASE_URL = 'https://apiv3.geoportail.lu/';\nconst LUX_PROTOCOL = 'https';\nconst LUX_I18N_URL = 'https://apiv3.geoportail.lu/static-ngeo/build/fr.json';\nconst LUX_STYLESHEET_URL = 'https://apiv3.geoportail.lu/static-ngeo/build/apiv3.css';\nconst LUX_VENDOR_URL = 'https://apiv3.geoportail.lu/static-ngeo/build/vendor.js';\nconst LUX_API_URL = 'https://apiv3.geoportail.lu/static-ngeo/build/apiv3.js';\n\nconst LUX_STYLESHEET_ID = 'geoportail-apiv3-css';\nconst LUX_VENDOR_SCRIPT_ID = 'geoportail-apiv3-vendor';\nconst LUX_API_SCRIPT_ID = 'geoportail-apiv3-script';\n\nconst ELEMENT_STATUS_ATTRIBUTE = 'data-geoportail-status';\n\nlet loadPromise: Promise<void> | null = null;\n\n/**\n * Loads the Geoportail API assets exactly once.\n * Safe to call multiple times — subsequent calls return the same promise.\n */\nexport function loadLuxApi(): Promise<void> {\n if (loadPromise) return loadPromise;\n\n if (typeof window === 'undefined' || typeof document === 'undefined') {\n return Promise.reject(new Error('loadLuxApi must be called in a browser environment'));\n }\n\n loadPromise = loadLuxApiInternal().catch((error: unknown) => {\n loadPromise = null;\n throw error instanceof Error ? error : new Error(String(error));\n });\n\n return loadPromise;\n}\n\n/**\n * The lux API may initialise asynchronously after the scripts load.\n * Poll until window.lux is defined (max ~5 s).\n */\nfunction pollForLux(resolve: () => void, reject: (err: Error) => void): void {\n const maxAttempts = 100;\n let attempts = 0;\n\n const check = () => {\n if (window.lux) {\n resolve();\n return;\n }\n if (attempts++ >= maxAttempts) {\n loadPromise = null;\n reject(new Error('Timed out waiting for window.lux to be defined'));\n return;\n }\n setTimeout(check, 50);\n };\n\n check();\n}\n\nasync function loadLuxApiInternal(): Promise<void> {\n if (window.lux) {\n configureLux(window.lux);\n return;\n }\n\n await loadStylesheetOnce(LUX_STYLESHEET_ID, LUX_STYLESHEET_URL);\n await loadScriptOnce(LUX_VENDOR_SCRIPT_ID, LUX_VENDOR_URL);\n await loadScriptOnce(LUX_API_SCRIPT_ID, LUX_API_URL);\n await waitForLux();\n configureLux(window.lux!);\n}\n\nfunction waitForLux(): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n pollForLux(resolve, reject);\n });\n}\n\nfunction configureLux(lux: NonNullable<Window['lux']>): void {\n lux.setBaseUrl(LUX_BASE_URL, LUX_PROTOCOL);\n lux.setI18nUrl(LUX_I18N_URL);\n}\n\nfunction loadScriptOnce(id: string, src: string): Promise<void> {\n const existing = document.getElementById(id) as HTMLScriptElement | null;\n if (existing) {\n return waitForElementLoad(existing, src, 'script');\n }\n\n return new Promise<void>((resolve, reject) => {\n const script = document.createElement('script');\n script.id = id;\n script.src = src;\n script.async = false;\n script.setAttribute(ELEMENT_STATUS_ATTRIBUTE, 'loading');\n\n const cleanup = attachLoadHandlers(\n script,\n () => resolve(),\n () => reject(new Error(`Failed to load Geoportail script from ${src}`)),\n 'script'\n );\n\n document.head.appendChild(script);\n void cleanup;\n });\n}\n\nfunction loadStylesheetOnce(id: string, href: string): Promise<void> {\n const existing = document.getElementById(id) as HTMLLinkElement | null;\n if (existing) {\n return waitForElementLoad(existing, href, 'stylesheet');\n }\n\n return new Promise<void>((resolve, reject) => {\n const link = document.createElement('link');\n link.id = id;\n link.rel = 'stylesheet';\n link.href = href;\n link.setAttribute(ELEMENT_STATUS_ATTRIBUTE, 'loading');\n\n const cleanup = attachLoadHandlers(\n link,\n () => resolve(),\n () => reject(new Error(`Failed to load Geoportail stylesheet from ${href}`)),\n 'stylesheet'\n );\n\n document.head.appendChild(link);\n void cleanup;\n });\n}\n\nfunction waitForElementLoad(\n element: HTMLScriptElement | HTMLLinkElement,\n resourceUrl: string,\n kind: 'script' | 'stylesheet'\n): Promise<void> {\n const status = element.getAttribute(ELEMENT_STATUS_ATTRIBUTE);\n\n if (status === 'loaded') {\n return Promise.resolve();\n }\n\n if (status === 'error') {\n element.remove();\n return Promise.reject(new Error(`Failed to load Geoportail ${kind} from ${resourceUrl}`));\n }\n\n return new Promise<void>((resolve, reject) => {\n const cleanup = attachLoadHandlers(\n element,\n () => resolve(),\n () => reject(new Error(`Failed to load Geoportail ${kind} from ${resourceUrl}`)),\n kind\n );\n\n void cleanup;\n });\n}\n\nfunction attachLoadHandlers(\n element: HTMLScriptElement | HTMLLinkElement,\n onLoad: () => void,\n onError: () => void,\n kind: 'script' | 'stylesheet'\n): () => void {\n const handleLoad = () => {\n element.setAttribute(ELEMENT_STATUS_ATTRIBUTE, 'loaded');\n cleanup();\n onLoad();\n };\n\n const handleError = () => {\n element.setAttribute(ELEMENT_STATUS_ATTRIBUTE, 'error');\n cleanup();\n element.remove();\n onError();\n };\n\n const cleanup = () => {\n element.removeEventListener('load', handleLoad);\n element.removeEventListener('error', handleError);\n };\n\n element.addEventListener('load', handleLoad, { once: true });\n element.addEventListener('error', handleError, { once: true });\n\n if (kind === 'stylesheet') {\n const link = element as HTMLLinkElement;\n if (link.sheet) {\n handleLoad();\n }\n } else {\n const script = element as HTMLScriptElement;\n if (script.dataset.geoportailStatus === 'loaded') {\n handleLoad();\n }\n }\n\n return cleanup;\n}\n","import { useState, useEffect } from 'react';\nimport { loadLuxApi } from '../utils/loader';\nimport type { LuxNamespace } from '../types/lux';\n\nexport type LuxApiState =\n | { status: 'loading'; lux: null; error: null }\n | { status: 'ready'; lux: LuxNamespace; error: null }\n | { status: 'error'; lux: null; error: Error };\n\n/**\n * Loads the Geoportail runtime assets and returns the `lux` namespace once ready.\n * Deduplicates the asset load — safe to call from multiple components.\n */\nexport function useLuxApi(): LuxApiState {\n const [state, setState] = useState<LuxApiState>({\n status: 'loading',\n lux: null,\n error: null,\n });\n\n useEffect(() => {\n let cancelled = false;\n\n loadLuxApi()\n .then(() => {\n if (!cancelled) {\n setState({ status: 'ready', lux: window.lux!, error: null });\n }\n })\n .catch((err: unknown) => {\n if (!cancelled) {\n setState({\n status: 'error',\n lux: null,\n error: err instanceof Error ? err : new Error(String(err)),\n });\n }\n });\n\n return () => {\n cancelled = true;\n };\n }, []);\n\n return state;\n}\n","/**\n * Coordinate conversion between EPSG:2169 (Luxembourg TM) and EPSG:4326 (WGS84).\n *\n * The Geoportail API operates internally in EPSG:2169 but also accepts\n * position arrays in EPSG:4326 via `lux.Map` constructor options.\n *\n * For precise server-side conversion the REST API itself is authoritative.\n * The formulas below use a 6-parameter Helmert + transverse Mercator approach\n * sufficient for Luxembourg's territory (~50 km radius).\n *\n * Reference: IGN-L / ACT official parameters for LUREF (EPSG:2169).\n */\n\n// LUREF / Luxembourg TM projection constants (EPSG:2169)\nconst FE = 80000; // False Easting (m)\nconst FN = 100000; // False Northing (m)\nconst LON0 = 6.16666666666667; // Central meridian (6°10') in degrees\nconst LAT0 = 49.8333333333333; // Latitude of origin (49°50') in degrees\nconst SCALE = 1.0; // Scale factor at central meridian\nconst A = 6378388.0; // Semi-major axis (Hayford / International 1924)\nconst F = 1 / 297.0; // Flattening\nconst B = A * (1 - F); // Semi-minor axis\n\nconst E2 = 1 - (B * B) / (A * A); // First eccentricity squared\n\n// Helmert 7-parameter shift: ETRS89 -> ED50 (approximate for Luxembourg)\n// These values transform WGS84 (≈ETRS89) to ED50 used by LUREF\nconst DX = -87.0;\nconst DY = -98.0;\nconst DZ = -121.0;\n\nfunction degToRad(d: number): number {\n return (d * Math.PI) / 180;\n}\n\nfunction radToDeg(r: number): number {\n return (r * 180) / Math.PI;\n}\n\n/**\n * Molodensky transformation: WGS84 -> ED50 (approximate, <1 m accuracy).\n */\nfunction wgs84ToEd50(\n lat: number,\n lon: number\n): { lat: number; lon: number } {\n const latR = degToRad(lat);\n const lonR = degToRad(lon);\n\n const sinLat = Math.sin(latR);\n const cosLat = Math.cos(latR);\n const sinLon = Math.sin(lonR);\n const cosLon = Math.cos(lonR);\n\n const aWgs = 6378137.0;\n const fWgs = 1 / 298.257223563;\n const bWgs = aWgs * (1 - fWgs);\n const e2Wgs = 1 - (bWgs * bWgs) / (aWgs * aWgs);\n\n const da = A - aWgs;\n const df = F - fWgs;\n\n const N = aWgs / Math.sqrt(1 - e2Wgs * sinLat * sinLat);\n const M =\n (aWgs * (1 - e2Wgs)) /\n Math.pow(1 - e2Wgs * sinLat * sinLat, 1.5);\n\n const dLat =\n (1 / M) *\n (N * (e2Wgs / (1 - e2Wgs)) * sinLat * cosLat * (da / aWgs) +\n (N / aWgs + 1) * sinLat * cosLat * df * (aWgs / bWgs) -\n (DX * sinLat * cosLon + DY * sinLat * sinLon - DZ * cosLat));\n\n const dLon =\n (1 / (N * cosLat)) * (-DX * sinLon + DY * cosLon);\n\n return {\n lat: lat + radToDeg(dLat),\n lon: lon + radToDeg(dLon),\n };\n}\n\n/**\n * ED50 -> WGS84 (inverse Molodensky, approximate).\n */\nfunction ed50ToWgs84(\n lat: number,\n lon: number\n): { lat: number; lon: number } {\n const latR = degToRad(lat);\n const lonR = degToRad(lon);\n\n const sinLat = Math.sin(latR);\n const cosLat = Math.cos(latR);\n const sinLon = Math.sin(lonR);\n const cosLon = Math.cos(lonR);\n\n const N = A / Math.sqrt(1 - E2 * sinLat * sinLat);\n const M = (A * (1 - E2)) / Math.pow(1 - E2 * sinLat * sinLat, 1.5);\n\n const da = 6378137.0 - A;\n const fWgs = 1 / 298.257223563;\n const df = fWgs - F;\n\n const dLat =\n (1 / M) *\n (N * (E2 / (1 - E2)) * sinLat * cosLat * (da / A) +\n (N / A + 1) * sinLat * cosLat * df * (A / B) +\n (DX * sinLat * cosLon + DY * sinLat * sinLon - DZ * cosLat));\n\n const dLon =\n (1 / (N * cosLat)) * (DX * sinLon - DY * cosLon);\n\n return {\n lat: lat + radToDeg(dLat),\n lon: lon + radToDeg(dLon),\n };\n}\n\n/**\n * Transverse Mercator forward projection (ED50 lat/lon -> LUREF easting/northing).\n */\nfunction tmForward(lat: number, lon: number): { easting: number; northing: number } {\n const latR = degToRad(lat);\n const lonR = degToRad(lon);\n const lon0R = degToRad(LON0);\n const lat0R = degToRad(LAT0);\n\n const sinLat = Math.sin(latR);\n const cosLat = Math.cos(latR);\n const tanLat = Math.tan(latR);\n\n const N = A / Math.sqrt(1 - E2 * sinLat * sinLat);\n const T = tanLat * tanLat;\n const C = (E2 / (1 - E2)) * cosLat * cosLat;\n const dl = lonR - lon0R;\n const XX = cosLat * dl;\n\n // Meridian arc from equator to lat\n const M = meridianArc(latR);\n const M0 = meridianArc(lat0R);\n\n const easting =\n FE +\n SCALE *\n N *\n (XX +\n (XX * XX * XX * (1 - T + C)) / 6 +\n (XX * XX * XX * XX * XX * (5 - 18 * T + T * T + 72 * C)) / 120);\n\n const northing =\n FN +\n SCALE *\n (M -\n M0 +\n N *\n tanLat *\n (XX * XX / 2 +\n (XX * XX * XX * XX * (5 - T + 9 * C + 4 * C * C)) / 24 +\n (XX * XX * XX * XX * XX * XX *\n (61 - 58 * T + T * T + 600 * C)) /\n 720));\n\n return { easting, northing };\n}\n\n/**\n * Transverse Mercator inverse projection (LUREF easting/northing -> ED50 lat/lon).\n */\nfunction tmInverse(easting: number, northing: number): { lat: number; lon: number } {\n const x = easting - FE;\n const y = northing - FN;\n const lat0R = degToRad(LAT0);\n const lon0R = degToRad(LON0);\n const M0 = meridianArc(lat0R);\n\n // Footpoint latitude\n const M1 = M0 + y / SCALE;\n const mu = M1 / (A * (1 - E2 / 4 - (3 * E2 * E2) / 64));\n\n const e1 = (1 - Math.sqrt(1 - E2)) / (1 + Math.sqrt(1 - E2));\n const phi1 =\n mu +\n ((3 * e1) / 2 - (27 * e1 * e1 * e1) / 32) * Math.sin(2 * mu) +\n ((21 * e1 * e1) / 16 - (55 * e1 * e1 * e1 * e1) / 32) *\n Math.sin(4 * mu) +\n ((151 * e1 * e1 * e1) / 96) * Math.sin(6 * mu);\n\n const sinPhi1 = Math.sin(phi1);\n const cosPhi1 = Math.cos(phi1);\n const tanPhi1 = Math.tan(phi1);\n\n const N1 = A / Math.sqrt(1 - E2 * sinPhi1 * sinPhi1);\n const T1 = tanPhi1 * tanPhi1;\n const C1 = (E2 / (1 - E2)) * cosPhi1 * cosPhi1;\n const R1 =\n (A * (1 - E2)) / Math.pow(1 - E2 * sinPhi1 * sinPhi1, 1.5);\n const D = x / (N1 * SCALE);\n\n const lat =\n phi1 -\n ((N1 * tanPhi1) / R1) *\n (D * D / 2 -\n (D * D * D * D * (5 + 3 * T1 + 10 * C1 - 4 * C1 * C1)) / 24 +\n (D * D * D * D * D * D *\n (61 + 90 * T1 + 298 * C1 + 45 * T1 * T1)) /\n 720);\n\n const lon =\n lon0R +\n (D -\n (D * D * D * (1 + 2 * T1 + C1)) / 6 +\n (D * D * D * D * D * (5 - 2 * C1 + 28 * T1 - 3 * C1 * C1)) / 120) /\n cosPhi1;\n\n return { lat: radToDeg(lat), lon: radToDeg(lon) };\n}\n\nfunction meridianArc(latR: number): number {\n const e2 = E2;\n const e4 = e2 * e2;\n const e6 = e4 * e2;\n return (\n A *\n ((1 - e2 / 4 - (3 * e4) / 64 - (5 * e6) / 256) * latR -\n ((3 * e2) / 8 + (3 * e4) / 32 + (45 * e6) / 1024) *\n Math.sin(2 * latR) +\n ((15 * e4) / 256 + (45 * e6) / 1024) * Math.sin(4 * latR) -\n ((35 * e6) / 3072) * Math.sin(6 * latR))\n );\n}\n\n/**\n * Convert WGS84 (lat/lon) to EPSG:2169 (easting/northing).\n */\nexport function latLonToLuref(\n lat: number,\n lon: number\n): { easting: number; northing: number } {\n const ed50 = wgs84ToEd50(lat, lon);\n return tmForward(ed50.lat, ed50.lon);\n}\n\n/**\n * Convert EPSG:2169 (easting/northing) to WGS84 (lat/lon).\n */\nexport function lurefToLatLon(\n easting: number,\n northing: number\n): { lat: number; lon: number } {\n const ed50 = tmInverse(easting, northing);\n return ed50ToWgs84(ed50.lat, ed50.lon);\n}\n","import React, {\n useEffect,\n useRef,\n forwardRef,\n useImperativeHandle,\n} from 'react';\nimport { useLuxApi } from '../hooks/useLuxApi';\nimport { lurefToLatLon, latLonToLuref } from '../utils/coordinates';\nimport type { LatLon, MapClickHandler, MarkerMode } from '../types';\nimport type { LuxMapInstance } from '../types/lux';\n\nexport interface GeoportailMapProps {\n /**\n * Initial center of the map.\n * Defaults to Luxembourg City (lat: 49.6116, lon: 6.1319).\n */\n center?: LatLon;\n\n /** Initial zoom level (1–20). Default: 12 */\n zoom?: number;\n\n /**\n * Background layer identifier.\n * Default: 'basemap_2015_global'\n */\n bgLayer?: string;\n\n /**\n * Controls pin/marker behaviour:\n * - 'none' — no marker\n * - 'fixed' — show a marker at `markerPosition` (does not move on click)\n * - 'click' — user clicks map to place/move the pin; fires `onMarkerPlace`\n *\n * Default: 'none'\n */\n markerMode?: MarkerMode;\n\n /**\n * Position of the marker when `markerMode` is 'fixed' or to pre-set an\n * initial pin when `markerMode` is 'click'.\n */\n markerPosition?: LatLon;\n\n /**\n * Called whenever the user places a pin (markerMode === 'click').\n * Receives the WGS84 lat/lon of the clicked point.\n */\n onMarkerPlace?: MapClickHandler;\n\n /** CSS class applied to the map container div */\n className?: string;\n\n /** Inline styles for the map container div */\n style?: React.CSSProperties;\n\n /** Additional numeric layer IDs to add on top of the background */\n layers?: number[];\n}\n\nexport interface GeoportailMapHandle {\n /** Returns the underlying lux.Map instance (or null before ready) */\n getLuxMap(): LuxMapInstance | null;\n /** Programmatically move the map center */\n setCenter(coords: LatLon): void;\n /** Programmatically set zoom */\n setZoom(zoom: number): void;\n}\n\nconst LUXEMBOURG_CITY: LatLon = { lat: 49.6116, lon: 6.1319 };\nconst DEFAULT_BG_LAYER = 'basemap_2015_global';\n\n/**\n * Renders a Geoportail Luxembourg map inside a React component.\n *\n * Expose a ref (`GeoportailMapHandle`) to access the underlying lux.Map instance\n * or imperatively control the view.\n */\nexport const GeoportailMap = forwardRef<GeoportailMapHandle, GeoportailMapProps>(\n function GeoportailMap(\n {\n center = LUXEMBOURG_CITY,\n zoom = 12,\n bgLayer = DEFAULT_BG_LAYER,\n markerMode = 'none',\n markerPosition,\n onMarkerPlace,\n className,\n style,\n layers,\n },\n ref\n ) {\n const luxApi = useLuxApi();\n const mapContainerRef = useRef<HTMLDivElement | null>(null);\n const mapRef = useRef<LuxMapInstance | null>(null);\n const markerLayerRef = useRef<unknown>(null);\n const clickListenerRef = useRef<((...args: unknown[]) => void) | null>(null);\n\n // Keep stable refs to callbacks so effects don't re-run on every render\n const onMarkerPlaceRef = useRef(onMarkerPlace);\n onMarkerPlaceRef.current = onMarkerPlace;\n\n // ------------------------------------------------------------------ map init\n useEffect(() => {\n if (luxApi.status !== 'ready') return;\n if (!mapContainerRef.current) return;\n\n const lux = luxApi.lux;\n const { easting, northing } = latLonToLuref(center.lat, center.lon);\n\n const mapInstance = new lux.Map({\n target: mapContainerRef.current,\n bgLayer,\n zoom,\n position: [easting, northing],\n ...(layers && layers.length > 0\n ? { layers, layerOpacities: layers.map(() => 1) }\n : {}),\n });\n\n mapRef.current = mapInstance;\n\n return () => {\n // lux.Map does not expose a destroy(); we clear our references\n mapRef.current = null;\n markerLayerRef.current = null;\n clickListenerRef.current = null;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [luxApi.status]);\n\n // ------------------------------------------------------------------ marker\n useEffect(() => {\n const map = mapRef.current;\n if (!map || luxApi.status !== 'ready') return;\n\n // Remove previous click listener\n if (clickListenerRef.current) {\n map.un('singleclick', clickListenerRef.current);\n clickListenerRef.current = null;\n }\n\n if (markerMode === 'none') {\n clearMarker(map, markerLayerRef);\n return;\n }\n\n const initialPos = markerPosition ?? (markerMode === 'fixed' ? center : undefined);\n if (initialPos) {\n placeMarker(map, initialPos, markerLayerRef);\n }\n\n if (markerMode === 'click') {\n const handler = (...args: unknown[]) => {\n // OpenLayers MapBrowserEvent — coordinate is in map projection (EPSG:2169)\n const evt = args[0] as { coordinate?: [number, number] };\n if (!evt.coordinate) return;\n\n const [e, n] = evt.coordinate;\n const latLon = lurefToLatLon(e, n);\n placeMarker(map, latLon, markerLayerRef);\n onMarkerPlaceRef.current?.(latLon);\n };\n\n clickListenerRef.current = handler;\n map.on('singleclick', handler);\n }\n }, [\n luxApi.status,\n markerMode,\n markerPosition?.lat,\n markerPosition?.lon,\n center.lat,\n center.lon,\n ]);\n\n // ------------------------------------------------------------------ imperative handle\n useImperativeHandle(ref, () => ({\n getLuxMap: () => mapRef.current,\n setCenter(coords: LatLon) {\n const map = mapRef.current;\n if (!map) return;\n const { easting, northing } = latLonToLuref(coords.lat, coords.lon);\n map.getView().setCenter([easting, northing]);\n },\n setZoom(z: number) {\n mapRef.current?.getView().setZoom(z);\n },\n }));\n\n // ------------------------------------------------------------------ render\n if (luxApi.status === 'error') {\n return (\n <div\n className={className}\n style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', background: '#f5f5f5', ...style }}\n >\n <span style={{ color: '#c00' }}>\n Failed to load Geoportail API: {luxApi.error.message}\n </span>\n </div>\n );\n }\n\n return (\n <div style={{ position: 'relative', ...style }} className={className}>\n {luxApi.status === 'loading' && (\n <div\n style={{\n position: 'absolute',\n inset: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n background: 'rgba(255,255,255,0.7)',\n zIndex: 10,\n }}\n >\n <span>Loading map…</span>\n </div>\n )}\n <div\n ref={mapContainerRef}\n style={{ width: '100%', height: '100%' }}\n />\n </div>\n );\n }\n);\n\n// ------------------------------------------------------------------ helpers\n\n/**\n * Place/move an SVG pin marker on the map.\n * lux.Map is built on OpenLayers 3 — we use ol.Overlay for the marker.\n */\nfunction placeMarker(\n map: LuxMapInstance,\n position: LatLon,\n layerRef: React.MutableRefObject<unknown>\n): void {\n // Prefer ol (OpenLayers global) if available\n const ol = (window as unknown as { ol?: OlLike }).ol;\n if (!ol) return;\n\n const { easting, northing } = latLonToLuref(position.lat, position.lon);\n\n // Reuse existing overlay or create a new one\n if (layerRef.current) {\n const overlay = layerRef.current as OlOverlay;\n overlay.setPosition([easting, northing]);\n return;\n }\n\n const el = document.createElement('div');\n el.innerHTML = PIN_SVG;\n el.style.cssText =\n 'cursor:pointer;transform:translate(-50%,-100%);line-height:0;';\n\n const overlay = new ol.Overlay({\n element: el,\n positioning: 'bottom-center',\n stopEvent: false,\n });\n\n overlay.setPosition([easting, northing]);\n (map as unknown as { addOverlay(o: OlOverlay): void }).addOverlay(overlay);\n layerRef.current = overlay;\n}\n\nfunction clearMarker(\n _map: LuxMapInstance,\n layerRef: React.MutableRefObject<unknown>\n): void {\n if (!layerRef.current) return;\n const ol = (window as unknown as { ol?: OlLike }).ol;\n if (!ol) return;\n // Overlay doesn't have a built-in remove on the overlay itself;\n // set position to undefined to hide it\n (layerRef.current as OlOverlay).setPosition(undefined);\n layerRef.current = null;\n}\n\n// Minimal pin SVG (red teardrop, 30×40)\nconst PIN_SVG = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"30\" height=\"40\" viewBox=\"0 0 30 40\">\n <path d=\"M15 0C7.268 0 1 6.268 1 14c0 10.5 14 26 14 26S29 24.5 29 14C29 6.268 22.732 0 15 0z\"\n fill=\"#e53935\" stroke=\"#b71c1c\" stroke-width=\"1.5\"/>\n <circle cx=\"15\" cy=\"14\" r=\"5\" fill=\"white\"/>\n</svg>`;\n\n// Minimal OL type stubs used only within this file\ninterface OlOverlay {\n setPosition(pos: [number, number] | undefined): void;\n}\n\ninterface OlLike {\n Overlay: new (opts: { element: HTMLElement; positioning: string; stopEvent: boolean }) => OlOverlay;\n}\n","import { useState, useEffect, useCallback, useRef } from 'react';\nimport { latLonToLuref } from '../utils/coordinates';\nimport type { LatLon, Address } from '../types';\n\nconst REVERSE_GEOCODE_URL = 'https://api.geoportail.lu/geocoder/reverseGeocode';\n\nexport type ReverseGeocodeState =\n | { status: 'idle'; address: null; error: null }\n | { status: 'loading'; address: null; error: null }\n | { status: 'success'; address: Address; error: null }\n | { status: 'error'; address: null; error: Error };\n\n/**\n * Hook for reverse geocoding: convert a WGS84 lat/lon to a Luxembourg address.\n *\n * Uses the Geoportail REST reverse geocode endpoint — no API key required.\n *\n * @example\n * const { state, lookup } = useReverseGeocode();\n * // ...\n * lookup({ lat: 49.6116, lon: 6.1319 });\n * if (state.status === 'success') console.log(state.address.label);\n */\nexport function useReverseGeocode() {\n const [state, setState] = useState<ReverseGeocodeState>({\n status: 'idle',\n address: null,\n error: null,\n });\n\n const abortRef = useRef<AbortController | null>(null);\n\n useEffect(() => () => { abortRef.current?.abort(); }, []);\n\n const lookup = useCallback(async (position: LatLon) => {\n // Cancel any in-flight request\n abortRef.current?.abort();\n const controller = new AbortController();\n abortRef.current = controller;\n\n setState({ status: 'loading', address: null, error: null });\n\n try {\n const { easting, northing } = latLonToLuref(position.lat, position.lon);\n\n const url = new URL(REVERSE_GEOCODE_URL);\n url.searchParams.set('easting', String(easting));\n url.searchParams.set('northing', String(northing));\n\n const res = await fetch(url.toString(), { signal: controller.signal });\n\n if (!res.ok) {\n throw new Error(`Reverse geocode request failed: ${res.status} ${res.statusText}`);\n }\n\n const data = (await res.json()) as {\n results?: Array<{\n easting: number;\n northing: number;\n name?: string;\n distance?: number;\n }>;\n };\n\n const first = data.results?.[0];\n if (!first) {\n throw new Error('No results returned for this position');\n }\n\n setState({\n status: 'success',\n address: {\n label: first.name ?? '',\n distance: first.distance ?? 0,\n easting: first.easting,\n northing: first.northing,\n },\n error: null,\n });\n } catch (err: unknown) {\n if (err instanceof DOMException && err.name === 'AbortError') return;\n setState({\n status: 'error',\n address: null,\n error: err instanceof Error ? err : new Error(String(err)),\n });\n }\n }, []);\n\n const reset = useCallback(() => {\n abortRef.current?.abort();\n setState({ status: 'idle', address: null, error: null });\n }, []);\n\n return { state, lookup, reset };\n}\n","import { useState, useEffect, useCallback, useRef } from 'react';\nimport { lurefToLatLon } from '../utils/coordinates';\nimport type { GeocodeQuery, LatLon } from '../types';\n\nconst GEOCODE_URL = 'https://apiv3.geoportail.lu/geocode/search';\n\nexport interface GeocodeResultItem {\n latLon: LatLon;\n easting: number;\n northing: number;\n accuracy: number;\n street?: string;\n num?: string;\n zip?: string;\n locality?: string;\n}\n\nexport type GeocodeState =\n | { status: 'idle'; results: null; error: null }\n | { status: 'loading'; results: null; error: null }\n | { status: 'success'; results: GeocodeResultItem[]; error: null }\n | { status: 'error'; results: null; error: Error };\n\n/**\n * Hook for forward geocoding: search for a Luxembourg address and get coordinates.\n *\n * @example\n * const { state, search } = useGeocode();\n * search({ queryString: '1 rue du Fort Thüngen, Luxembourg' });\n * if (state.status === 'success') {\n * const { lat, lon } = state.results[0].latLon;\n * }\n */\nexport function useGeocode() {\n const [state, setState] = useState<GeocodeState>({\n status: 'idle',\n results: null,\n error: null,\n });\n\n const abortRef = useRef<AbortController | null>(null);\n\n useEffect(() => () => { abortRef.current?.abort(); }, []);\n\n const search = useCallback(async (query: GeocodeQuery) => {\n abortRef.current?.abort();\n const controller = new AbortController();\n abortRef.current = controller;\n\n setState({ status: 'loading', results: null, error: null });\n\n try {\n const url = new URL(GEOCODE_URL);\n\n if (query.queryString) {\n url.searchParams.set('queryString', query.queryString);\n } else {\n if (query.num) url.searchParams.set('num', query.num);\n if (query.street) url.searchParams.set('street', query.street);\n if (query.zip) url.searchParams.set('zip', query.zip);\n if (query.locality) url.searchParams.set('locality', query.locality);\n }\n\n const res = await fetch(url.toString(), { signal: controller.signal });\n\n if (!res.ok) {\n throw new Error(`Geocode request failed: ${res.status} ${res.statusText}`);\n }\n\n const data = (await res.json()) as {\n results?: Array<{\n easting: number;\n northing: number;\n accuracy?: number;\n AddressDetails?: {\n street?: string;\n number?: string;\n zip?: string;\n locality?: string;\n };\n }>;\n };\n\n const results: GeocodeResultItem[] = (data.results ?? []).map((r) => ({\n latLon: lurefToLatLon(r.easting, r.northing),\n easting: r.easting,\n northing: r.northing,\n accuracy: r.accuracy ?? 0,\n street: r.AddressDetails?.street,\n num: r.AddressDetails?.number,\n zip: r.AddressDetails?.zip,\n locality: r.AddressDetails?.locality,\n }));\n\n setState({ status: 'success', results, error: null });\n } catch (err: unknown) {\n if (err instanceof DOMException && err.name === 'AbortError') return;\n setState({\n status: 'error',\n results: null,\n error: err instanceof Error ? err : new Error(String(err)),\n });\n }\n }, []);\n\n const reset = useCallback(() => {\n abortRef.current?.abort();\n setState({ status: 'idle', results: null, error: null });\n }, []);\n\n return { state, search, reset };\n}\n"],"names":["LUX_BASE_URL","LUX_PROTOCOL","LUX_I18N_URL","LUX_STYLESHEET_URL","LUX_VENDOR_URL","LUX_API_URL","LUX_STYLESHEET_ID","LUX_VENDOR_SCRIPT_ID","LUX_API_SCRIPT_ID","ELEMENT_STATUS_ATTRIBUTE","loadPromise","loadLuxApi","loadLuxApiInternal","error","pollForLux","resolve","reject","attempts","check","configureLux","loadStylesheetOnce","loadScriptOnce","waitForLux","lux","id","src","existing","waitForElementLoad","script","attachLoadHandlers","href","link","element","resourceUrl","kind","status","onLoad","onError","handleLoad","cleanup","handleError","useLuxApi","state","setState","useState","useEffect","cancelled","err","FE","FN","LON0","LAT0","SCALE","A","F","B","E2","DX","DY","DZ","degToRad","d","radToDeg","r","wgs84ToEd50","lat","lon","latR","lonR","sinLat","cosLat","sinLon","cosLon","aWgs","fWgs","bWgs","e2Wgs","da","df","N","dLat","dLon","ed50ToWgs84","M","tmForward","lon0R","lat0R","tanLat","T","C","dl","XX","meridianArc","M0","easting","northing","tmInverse","x","y","mu","e1","phi1","sinPhi1","cosPhi1","tanPhi1","N1","T1","C1","R1","D","e2","e4","e6","latLonToLuref","ed50","lurefToLatLon","LUXEMBOURG_CITY","DEFAULT_BG_LAYER","GeoportailMap","forwardRef","center","zoom","bgLayer","markerMode","markerPosition","onMarkerPlace","className","style","layers","ref","luxApi","mapContainerRef","useRef","mapRef","markerLayerRef","clickListenerRef","onMarkerPlaceRef","mapInstance","map","clearMarker","initialPos","placeMarker","handler","args","evt","e","n","latLon","_a","useImperativeHandle","coords","z","jsx","jsxs","position","layerRef","ol","overlay","el","PIN_SVG","_map","REVERSE_GEOCODE_URL","useReverseGeocode","abortRef","lookup","useCallback","controller","url","res","first","_b","reset","GEOCODE_URL","useGeocode","search","query","results","_c","_d"],"mappings":"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"}
1
+ {"version":3,"file":"react-geoportail.js","sources":["../src/utils/loader.ts","../src/hooks/useLuxApi.ts","../src/utils/coordinates.ts","../src/components/GeoportailMap.tsx","../src/hooks/useReverseGeocode.ts","../src/hooks/useGeocode.ts"],"sourcesContent":["/**\n * Dynamically injects the Geoportail v3 assets and resolves when\n * the global `lux` namespace is available.\n */\n\nconst LUX_BASE_URL = 'https://apiv3.geoportail.lu/';\nconst LUX_PROTOCOL = 'https';\nconst LUX_I18N_URL = 'https://apiv3.geoportail.lu/static-ngeo/build/fr.json';\nconst LUX_STYLESHEET_URL = 'https://apiv3.geoportail.lu/static-ngeo/build/apiv3.css';\nconst LUX_VENDOR_URL = 'https://apiv3.geoportail.lu/static-ngeo/build/vendor.js';\nconst LUX_API_URL = 'https://apiv3.geoportail.lu/static-ngeo/build/apiv3.js';\n\nconst LUX_STYLESHEET_ID = 'geoportail-apiv3-css';\nconst LUX_VENDOR_SCRIPT_ID = 'geoportail-apiv3-vendor';\nconst LUX_API_SCRIPT_ID = 'geoportail-apiv3-script';\n\nconst ELEMENT_STATUS_ATTRIBUTE = 'data-geoportail-status';\n\nlet loadPromise: Promise<void> | null = null;\n\n/**\n * Loads the Geoportail API assets exactly once.\n * Safe to call multiple times — subsequent calls return the same promise.\n */\nexport function loadLuxApi(): Promise<void> {\n if (loadPromise) return loadPromise;\n\n if (typeof window === 'undefined' || typeof document === 'undefined') {\n return Promise.reject(new Error('loadLuxApi must be called in a browser environment'));\n }\n\n loadPromise = loadLuxApiInternal().catch((error: unknown) => {\n loadPromise = null;\n throw error instanceof Error ? error : new Error(String(error));\n });\n\n return loadPromise;\n}\n\n/**\n * The lux API may initialise asynchronously after the scripts load.\n * Poll until window.lux is defined (max ~5 s).\n */\nfunction pollForLux(resolve: () => void, reject: (err: Error) => void): void {\n const maxAttempts = 100;\n let attempts = 0;\n\n const check = () => {\n if (window.lux) {\n resolve();\n return;\n }\n if (attempts++ >= maxAttempts) {\n loadPromise = null;\n reject(new Error('Timed out waiting for window.lux to be defined'));\n return;\n }\n setTimeout(check, 50);\n };\n\n check();\n}\n\nasync function loadLuxApiInternal(): Promise<void> {\n if (window.lux) {\n configureLux(window.lux);\n return;\n }\n\n await loadStylesheetOnce(LUX_STYLESHEET_ID, LUX_STYLESHEET_URL);\n await loadScriptOnce(LUX_VENDOR_SCRIPT_ID, LUX_VENDOR_URL);\n await loadScriptOnce(LUX_API_SCRIPT_ID, LUX_API_URL);\n await waitForLux();\n configureLux(window.lux!);\n}\n\nfunction waitForLux(): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n pollForLux(resolve, reject);\n });\n}\n\nfunction configureLux(lux: NonNullable<Window['lux']>): void {\n lux.setBaseUrl(LUX_BASE_URL, LUX_PROTOCOL);\n lux.setI18nUrl(LUX_I18N_URL);\n}\n\nfunction loadScriptOnce(id: string, src: string): Promise<void> {\n const existing = document.getElementById(id) as HTMLScriptElement | null;\n if (existing) {\n return waitForElementLoad(existing, src, 'script');\n }\n\n return new Promise<void>((resolve, reject) => {\n const script = document.createElement('script');\n script.id = id;\n script.src = src;\n script.async = false;\n script.setAttribute(ELEMENT_STATUS_ATTRIBUTE, 'loading');\n\n const cleanup = attachLoadHandlers(\n script,\n () => resolve(),\n () => reject(new Error(`Failed to load Geoportail script from ${src}`)),\n 'script'\n );\n\n document.head.appendChild(script);\n void cleanup;\n });\n}\n\nfunction loadStylesheetOnce(id: string, href: string): Promise<void> {\n const existing = document.getElementById(id) as HTMLLinkElement | null;\n if (existing) {\n return waitForElementLoad(existing, href, 'stylesheet');\n }\n\n return new Promise<void>((resolve, reject) => {\n const link = document.createElement('link');\n link.id = id;\n link.rel = 'stylesheet';\n link.href = href;\n link.setAttribute(ELEMENT_STATUS_ATTRIBUTE, 'loading');\n\n const cleanup = attachLoadHandlers(\n link,\n () => resolve(),\n () => reject(new Error(`Failed to load Geoportail stylesheet from ${href}`)),\n 'stylesheet'\n );\n\n document.head.appendChild(link);\n void cleanup;\n });\n}\n\nfunction waitForElementLoad(\n element: HTMLScriptElement | HTMLLinkElement,\n resourceUrl: string,\n kind: 'script' | 'stylesheet'\n): Promise<void> {\n const status = element.getAttribute(ELEMENT_STATUS_ATTRIBUTE);\n\n if (status === 'loaded') {\n return Promise.resolve();\n }\n\n if (status === 'error') {\n element.remove();\n return Promise.reject(new Error(`Failed to load Geoportail ${kind} from ${resourceUrl}`));\n }\n\n return new Promise<void>((resolve, reject) => {\n const cleanup = attachLoadHandlers(\n element,\n () => resolve(),\n () => reject(new Error(`Failed to load Geoportail ${kind} from ${resourceUrl}`)),\n kind\n );\n\n void cleanup;\n });\n}\n\nfunction attachLoadHandlers(\n element: HTMLScriptElement | HTMLLinkElement,\n onLoad: () => void,\n onError: () => void,\n kind: 'script' | 'stylesheet'\n): () => void {\n const handleLoad = () => {\n element.setAttribute(ELEMENT_STATUS_ATTRIBUTE, 'loaded');\n cleanup();\n onLoad();\n };\n\n const handleError = () => {\n element.setAttribute(ELEMENT_STATUS_ATTRIBUTE, 'error');\n cleanup();\n element.remove();\n onError();\n };\n\n const cleanup = () => {\n element.removeEventListener('load', handleLoad);\n element.removeEventListener('error', handleError);\n };\n\n element.addEventListener('load', handleLoad, { once: true });\n element.addEventListener('error', handleError, { once: true });\n\n if (kind === 'stylesheet') {\n const link = element as HTMLLinkElement;\n if (link.sheet) {\n handleLoad();\n }\n } else {\n const script = element as HTMLScriptElement;\n if (script.dataset.geoportailStatus === 'loaded') {\n handleLoad();\n }\n }\n\n return cleanup;\n}\n","import { useState, useEffect } from 'react';\nimport { loadLuxApi } from '../utils/loader';\nimport type { LuxNamespace } from '../types/lux';\n\nexport type LuxApiState =\n | { status: 'loading'; lux: null; error: null }\n | { status: 'ready'; lux: LuxNamespace; error: null }\n | { status: 'error'; lux: null; error: Error };\n\n/**\n * Loads the Geoportail runtime assets and returns the `lux` namespace once ready.\n * Deduplicates the asset load — safe to call from multiple components.\n */\nexport function useLuxApi(): LuxApiState {\n const [state, setState] = useState<LuxApiState>({\n status: 'loading',\n lux: null,\n error: null,\n });\n\n useEffect(() => {\n let cancelled = false;\n\n loadLuxApi()\n .then(() => {\n if (!cancelled) {\n setState({ status: 'ready', lux: window.lux!, error: null });\n }\n })\n .catch((err: unknown) => {\n if (!cancelled) {\n setState({\n status: 'error',\n lux: null,\n error: err instanceof Error ? err : new Error(String(err)),\n });\n }\n });\n\n return () => {\n cancelled = true;\n };\n }, []);\n\n return state;\n}\n","/**\n * Coordinate conversion between EPSG:2169 (Luxembourg TM) and EPSG:4326 (WGS84).\n *\n * The Geoportail API operates internally in EPSG:2169 but also accepts\n * position arrays in EPSG:4326 via `lux.Map` constructor options.\n *\n * For precise server-side conversion the REST API itself is authoritative.\n * The formulas below use a 6-parameter Helmert + transverse Mercator approach\n * sufficient for Luxembourg's territory (~50 km radius).\n *\n * Reference: IGN-L / ACT official parameters for LUREF (EPSG:2169).\n */\n\n// LUREF / Luxembourg TM projection constants (EPSG:2169)\nconst FE = 80000; // False Easting (m)\nconst FN = 100000; // False Northing (m)\nconst LON0 = 6.16666666666667; // Central meridian (6°10') in degrees\nconst LAT0 = 49.8333333333333; // Latitude of origin (49°50') in degrees\nconst SCALE = 1.0; // Scale factor at central meridian\nconst A = 6378388.0; // Semi-major axis (Hayford / International 1924)\nconst F = 1 / 297.0; // Flattening\nconst B = A * (1 - F); // Semi-minor axis\n\nconst E2 = 1 - (B * B) / (A * A); // First eccentricity squared\n\n// Helmert 7-parameter shift: ETRS89 -> ED50 (approximate for Luxembourg)\n// These values transform WGS84 (≈ETRS89) to ED50 used by LUREF\nconst DX = -87.0;\nconst DY = -98.0;\nconst DZ = -121.0;\n\nfunction degToRad(d: number): number {\n return (d * Math.PI) / 180;\n}\n\nfunction radToDeg(r: number): number {\n return (r * 180) / Math.PI;\n}\n\n/**\n * Molodensky transformation: WGS84 -> ED50 (approximate, <1 m accuracy).\n */\nfunction wgs84ToEd50(\n lat: number,\n lon: number\n): { lat: number; lon: number } {\n const latR = degToRad(lat);\n const lonR = degToRad(lon);\n\n const sinLat = Math.sin(latR);\n const cosLat = Math.cos(latR);\n const sinLon = Math.sin(lonR);\n const cosLon = Math.cos(lonR);\n\n const aWgs = 6378137.0;\n const fWgs = 1 / 298.257223563;\n const bWgs = aWgs * (1 - fWgs);\n const e2Wgs = 1 - (bWgs * bWgs) / (aWgs * aWgs);\n\n const da = A - aWgs;\n const df = F - fWgs;\n\n const N = aWgs / Math.sqrt(1 - e2Wgs * sinLat * sinLat);\n const M =\n (aWgs * (1 - e2Wgs)) /\n Math.pow(1 - e2Wgs * sinLat * sinLat, 1.5);\n\n const dLat =\n (1 / M) *\n (N * (e2Wgs / (1 - e2Wgs)) * sinLat * cosLat * (da / aWgs) +\n (N / aWgs + 1) * sinLat * cosLat * df * (aWgs / bWgs) -\n (DX * sinLat * cosLon + DY * sinLat * sinLon - DZ * cosLat));\n\n const dLon =\n (1 / (N * cosLat)) * (-DX * sinLon + DY * cosLon);\n\n return {\n lat: lat + radToDeg(dLat),\n lon: lon + radToDeg(dLon),\n };\n}\n\n/**\n * ED50 -> WGS84 (inverse Molodensky, approximate).\n */\nfunction ed50ToWgs84(\n lat: number,\n lon: number\n): { lat: number; lon: number } {\n const latR = degToRad(lat);\n const lonR = degToRad(lon);\n\n const sinLat = Math.sin(latR);\n const cosLat = Math.cos(latR);\n const sinLon = Math.sin(lonR);\n const cosLon = Math.cos(lonR);\n\n const N = A / Math.sqrt(1 - E2 * sinLat * sinLat);\n const M = (A * (1 - E2)) / Math.pow(1 - E2 * sinLat * sinLat, 1.5);\n\n const da = 6378137.0 - A;\n const fWgs = 1 / 298.257223563;\n const df = fWgs - F;\n\n const dLat =\n (1 / M) *\n (N * (E2 / (1 - E2)) * sinLat * cosLat * (da / A) +\n (N / A + 1) * sinLat * cosLat * df * (A / B) +\n (DX * sinLat * cosLon + DY * sinLat * sinLon - DZ * cosLat));\n\n const dLon =\n (1 / (N * cosLat)) * (DX * sinLon - DY * cosLon);\n\n return {\n lat: lat + radToDeg(dLat),\n lon: lon + radToDeg(dLon),\n };\n}\n\n/**\n * Transverse Mercator forward projection (ED50 lat/lon -> LUREF easting/northing).\n */\nfunction tmForward(lat: number, lon: number): { easting: number; northing: number } {\n const latR = degToRad(lat);\n const lonR = degToRad(lon);\n const lon0R = degToRad(LON0);\n const lat0R = degToRad(LAT0);\n\n const sinLat = Math.sin(latR);\n const cosLat = Math.cos(latR);\n const tanLat = Math.tan(latR);\n\n const N = A / Math.sqrt(1 - E2 * sinLat * sinLat);\n const T = tanLat * tanLat;\n const C = (E2 / (1 - E2)) * cosLat * cosLat;\n const dl = lonR - lon0R;\n const XX = cosLat * dl;\n\n // Meridian arc from equator to lat\n const M = meridianArc(latR);\n const M0 = meridianArc(lat0R);\n\n const easting =\n FE +\n SCALE *\n N *\n (XX +\n (XX * XX * XX * (1 - T + C)) / 6 +\n (XX * XX * XX * XX * XX * (5 - 18 * T + T * T + 72 * C)) / 120);\n\n const northing =\n FN +\n SCALE *\n (M -\n M0 +\n N *\n tanLat *\n (XX * XX / 2 +\n (XX * XX * XX * XX * (5 - T + 9 * C + 4 * C * C)) / 24 +\n (XX * XX * XX * XX * XX * XX *\n (61 - 58 * T + T * T + 600 * C)) /\n 720));\n\n return { easting, northing };\n}\n\n/**\n * Transverse Mercator inverse projection (LUREF easting/northing -> ED50 lat/lon).\n */\nfunction tmInverse(easting: number, northing: number): { lat: number; lon: number } {\n const x = easting - FE;\n const y = northing - FN;\n const lat0R = degToRad(LAT0);\n const lon0R = degToRad(LON0);\n const M0 = meridianArc(lat0R);\n\n // Footpoint latitude\n const M1 = M0 + y / SCALE;\n const mu = M1 / (A * (1 - E2 / 4 - (3 * E2 * E2) / 64));\n\n const e1 = (1 - Math.sqrt(1 - E2)) / (1 + Math.sqrt(1 - E2));\n const phi1 =\n mu +\n ((3 * e1) / 2 - (27 * e1 * e1 * e1) / 32) * Math.sin(2 * mu) +\n ((21 * e1 * e1) / 16 - (55 * e1 * e1 * e1 * e1) / 32) *\n Math.sin(4 * mu) +\n ((151 * e1 * e1 * e1) / 96) * Math.sin(6 * mu);\n\n const sinPhi1 = Math.sin(phi1);\n const cosPhi1 = Math.cos(phi1);\n const tanPhi1 = Math.tan(phi1);\n\n const N1 = A / Math.sqrt(1 - E2 * sinPhi1 * sinPhi1);\n const T1 = tanPhi1 * tanPhi1;\n const C1 = (E2 / (1 - E2)) * cosPhi1 * cosPhi1;\n const R1 =\n (A * (1 - E2)) / Math.pow(1 - E2 * sinPhi1 * sinPhi1, 1.5);\n const D = x / (N1 * SCALE);\n\n const lat =\n phi1 -\n ((N1 * tanPhi1) / R1) *\n (D * D / 2 -\n (D * D * D * D * (5 + 3 * T1 + 10 * C1 - 4 * C1 * C1)) / 24 +\n (D * D * D * D * D * D *\n (61 + 90 * T1 + 298 * C1 + 45 * T1 * T1)) /\n 720);\n\n const lon =\n lon0R +\n (D -\n (D * D * D * (1 + 2 * T1 + C1)) / 6 +\n (D * D * D * D * D * (5 - 2 * C1 + 28 * T1 - 3 * C1 * C1)) / 120) /\n cosPhi1;\n\n return { lat: radToDeg(lat), lon: radToDeg(lon) };\n}\n\nfunction meridianArc(latR: number): number {\n const e2 = E2;\n const e4 = e2 * e2;\n const e6 = e4 * e2;\n return (\n A *\n ((1 - e2 / 4 - (3 * e4) / 64 - (5 * e6) / 256) * latR -\n ((3 * e2) / 8 + (3 * e4) / 32 + (45 * e6) / 1024) *\n Math.sin(2 * latR) +\n ((15 * e4) / 256 + (45 * e6) / 1024) * Math.sin(4 * latR) -\n ((35 * e6) / 3072) * Math.sin(6 * latR))\n );\n}\n\n/**\n * Convert WGS84 (lat/lon) to EPSG:2169 (easting/northing).\n */\nexport function latLonToLuref(\n lat: number,\n lon: number\n): { easting: number; northing: number } {\n const ed50 = wgs84ToEd50(lat, lon);\n return tmForward(ed50.lat, ed50.lon);\n}\n\n/**\n * Convert EPSG:2169 (easting/northing) to WGS84 (lat/lon).\n */\nexport function lurefToLatLon(\n easting: number,\n northing: number\n): { lat: number; lon: number } {\n const ed50 = tmInverse(easting, northing);\n return ed50ToWgs84(ed50.lat, ed50.lon);\n}\n","import React, {\n useEffect,\n useRef,\n forwardRef,\n useImperativeHandle,\n} from 'react';\nimport { useLuxApi } from '../hooks/useLuxApi';\nimport { lurefToLatLon, latLonToLuref } from '../utils/coordinates';\nimport type { LatLon, MapClickHandler, MarkerMode } from '../types';\nimport type { LuxMapInstance } from '../types/lux';\n\nconst DEFAULT_CLICK_SOURCE_PROJECTION = 'EPSG:3857';\nconst WGS84_PROJECTION = 'EPSG:4326';\n\nexport interface GeoportailMapProps {\n /**\n * Initial center of the map.\n * Defaults to Luxembourg City (lat: 49.6116, lon: 6.1319).\n */\n center?: LatLon;\n\n /** Initial zoom level (1–20). Default: 12 */\n zoom?: number;\n\n /**\n * Background layer identifier.\n * Default: 'basemap_2015_global'\n */\n bgLayer?: string;\n\n /**\n * Controls pin/marker behaviour:\n * - 'none' — no marker\n * - 'fixed' — show a marker at `markerPosition` (does not move on click)\n * - 'click' — user clicks map to place/move the pin; fires `onMarkerPlace`\n *\n * Default: 'none'\n */\n markerMode?: MarkerMode;\n\n /**\n * Position of the marker when `markerMode` is 'fixed' or to pre-set an\n * initial pin when `markerMode` is 'click'.\n */\n markerPosition?: LatLon;\n\n /**\n * Called whenever the user places a pin (markerMode === 'click').\n * Receives the WGS84 lat/lon of the clicked point.\n */\n onMarkerPlace?: MapClickHandler;\n\n /** CSS class applied to the map container div */\n className?: string;\n\n /** Inline styles for the map container div */\n style?: React.CSSProperties;\n\n /** Additional numeric layer IDs to add on top of the background */\n layers?: number[];\n}\n\nexport interface GeoportailMapHandle {\n /** Returns the underlying lux.Map instance (or null before ready) */\n getLuxMap(): LuxMapInstance | null;\n /** Programmatically move the map center */\n setCenter(coords: LatLon): void;\n /** Programmatically set zoom */\n setZoom(zoom: number): void;\n}\n\nconst LUXEMBOURG_CITY: LatLon = { lat: 49.6116, lon: 6.1319 };\nconst DEFAULT_BG_LAYER = 'basemap_2015_global';\n\n/**\n * Renders a Geoportail Luxembourg map inside a React component.\n *\n * Expose a ref (`GeoportailMapHandle`) to access the underlying lux.Map instance\n * or imperatively control the view.\n */\nexport const GeoportailMap = forwardRef<GeoportailMapHandle, GeoportailMapProps>(\n function GeoportailMap(\n {\n center = LUXEMBOURG_CITY,\n zoom = 12,\n bgLayer = DEFAULT_BG_LAYER,\n markerMode = 'none',\n markerPosition,\n onMarkerPlace,\n className,\n style,\n layers,\n },\n ref\n ) {\n const luxApi = useLuxApi();\n const mapContainerRef = useRef<HTMLDivElement | null>(null);\n const mapRef = useRef<LuxMapInstance | null>(null);\n const markerLayerRef = useRef<unknown>(null);\n const clickListenerRef = useRef<((...args: unknown[]) => void) | null>(null);\n\n // Keep stable refs to callbacks so effects don't re-run on every render\n const onMarkerPlaceRef = useRef(onMarkerPlace);\n onMarkerPlaceRef.current = onMarkerPlace;\n\n // ------------------------------------------------------------------ map init\n useEffect(() => {\n if (luxApi.status !== 'ready') return;\n if (!mapContainerRef.current) return;\n\n const lux = luxApi.lux;\n const { easting, northing } = latLonToLuref(center.lat, center.lon);\n\n const mapInstance = new lux.Map({\n target: mapContainerRef.current,\n bgLayer,\n zoom,\n position: [easting, northing],\n ...(layers && layers.length > 0\n ? { layers, layerOpacities: layers.map(() => 1) }\n : {}),\n });\n\n mapRef.current = mapInstance;\n\n return () => {\n // lux.Map does not expose a destroy(); we clear our references\n mapRef.current = null;\n markerLayerRef.current = null;\n clickListenerRef.current = null;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [luxApi.status]);\n\n // ------------------------------------------------------------------ marker\n useEffect(() => {\n const map = mapRef.current;\n if (!map || luxApi.status !== 'ready') return;\n\n // Remove previous click listener\n if (clickListenerRef.current) {\n map.un('singleclick', clickListenerRef.current);\n clickListenerRef.current = null;\n }\n\n if (markerMode === 'none') {\n clearMarker(map, markerLayerRef);\n return;\n }\n\n const initialPos = markerPosition ?? (markerMode === 'fixed' ? center : undefined);\n if (initialPos) {\n placeMarker(map, initialPos, markerLayerRef);\n }\n\n if (markerMode === 'click') {\n const handler = (...args: unknown[]) => {\n // Raw OpenLayers click coordinates are in the map view projection, not WGS84/LUREF.\n const evt = args[0] as { coordinate?: [number, number] };\n if (!evt.coordinate) return;\n\n const latLon = convertMapClickCoordinateToLatLon(map, evt.coordinate);\n placeMarker(map, latLon, markerLayerRef);\n onMarkerPlaceRef.current?.(latLon);\n };\n\n clickListenerRef.current = handler;\n map.on('singleclick', handler);\n }\n }, [\n luxApi.status,\n markerMode,\n markerPosition?.lat,\n markerPosition?.lon,\n center.lat,\n center.lon,\n ]);\n\n // ------------------------------------------------------------------ imperative handle\n useImperativeHandle(ref, () => ({\n getLuxMap: () => mapRef.current,\n setCenter(coords: LatLon) {\n const map = mapRef.current;\n if (!map) return;\n const { easting, northing } = latLonToLuref(coords.lat, coords.lon);\n map.getView().setCenter([easting, northing]);\n },\n setZoom(z: number) {\n mapRef.current?.getView().setZoom(z);\n },\n }));\n\n // ------------------------------------------------------------------ render\n if (luxApi.status === 'error') {\n return (\n <div\n className={className}\n style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', background: '#f5f5f5', ...style }}\n >\n <span style={{ color: '#c00' }}>\n Failed to load Geoportail API: {luxApi.error.message}\n </span>\n </div>\n );\n }\n\n return (\n <div style={{ position: 'relative', ...style }} className={className}>\n {luxApi.status === 'loading' && (\n <div\n style={{\n position: 'absolute',\n inset: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n background: 'rgba(255,255,255,0.7)',\n zIndex: 10,\n }}\n >\n <span>Loading map…</span>\n </div>\n )}\n <div\n ref={mapContainerRef}\n style={{ width: '100%', height: '100%' }}\n />\n </div>\n );\n }\n);\n\n// ------------------------------------------------------------------ helpers\n\n/**\n * Place/move an SVG pin marker on the map.\n * lux.Map is built on OpenLayers 3 — we use ol.Overlay for the marker.\n */\nfunction placeMarker(\n map: LuxMapInstance,\n position: LatLon,\n layerRef: React.MutableRefObject<unknown>\n): void {\n // Prefer ol (OpenLayers global) if available\n const ol = (window as unknown as { ol?: OlLike }).ol;\n if (!ol) return;\n\n const { easting, northing } = latLonToLuref(position.lat, position.lon);\n\n // Reuse existing overlay or create a new one\n if (layerRef.current) {\n const overlay = layerRef.current as OlOverlay;\n overlay.setPosition([easting, northing]);\n return;\n }\n\n const el = document.createElement('div');\n el.innerHTML = PIN_SVG;\n el.style.cssText =\n 'cursor:pointer;transform:translate(-50%,-100%);line-height:0;';\n\n const overlay = new ol.Overlay({\n element: el,\n positioning: 'bottom-center',\n stopEvent: false,\n });\n\n overlay.setPosition([easting, northing]);\n (map as unknown as { addOverlay(o: OlOverlay): void }).addOverlay(overlay);\n layerRef.current = overlay;\n}\n\nfunction clearMarker(\n _map: LuxMapInstance,\n layerRef: React.MutableRefObject<unknown>\n): void {\n if (!layerRef.current) return;\n const ol = (window as unknown as { ol?: OlLike }).ol;\n if (!ol) return;\n // Overlay doesn't have a built-in remove on the overlay itself;\n // set position to undefined to hide it\n (layerRef.current as OlOverlay).setPosition(undefined);\n layerRef.current = null;\n}\n\n// Minimal pin SVG (red teardrop, 30×40)\nconst PIN_SVG = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"30\" height=\"40\" viewBox=\"0 0 30 40\">\n <path d=\"M15 0C7.268 0 1 6.268 1 14c0 10.5 14 26 14 26S29 24.5 29 14C29 6.268 22.732 0 15 0z\"\n fill=\"#e53935\" stroke=\"#b71c1c\" stroke-width=\"1.5\"/>\n <circle cx=\"15\" cy=\"14\" r=\"5\" fill=\"white\"/>\n</svg>`;\n\n// Minimal OL type stubs used only within this file\ninterface OlOverlay {\n setPosition(pos: [number, number] | undefined): void;\n}\n\ninterface OlLike {\n proj?: {\n transform(\n coordinate: [number, number],\n source: string,\n destination: string\n ): [number, number];\n };\n Overlay: new (opts: { element: HTMLElement; positioning: string; stopEvent: boolean }) => OlOverlay;\n}\n\ninterface LuxMapViewWithProjection {\n getProjection?(): { getCode?(): string } | undefined;\n}\n\nexport function convertMapClickCoordinateToLatLon(\n map: LuxMapInstance,\n coordinate: [number, number]\n): LatLon {\n const ol = (window as unknown as { ol?: OlLike }).ol;\n const transform = ol?.proj?.transform;\n\n if (!transform) {\n const [easting, northing] = coordinate;\n return lurefToLatLon(easting, northing);\n }\n\n const sourceProjection =\n (map.getView() as LuxMapViewWithProjection).getProjection?.()?.getCode?.() ??\n DEFAULT_CLICK_SOURCE_PROJECTION;\n\n const [lon, lat] = transform(coordinate, sourceProjection, WGS84_PROJECTION);\n return { lat, lon };\n}\n","import { useState, useEffect, useCallback, useRef } from 'react';\nimport { latLonToLuref } from '../utils/coordinates';\nimport type { LatLon, Address } from '../types';\n\nconst REVERSE_GEOCODE_URL = 'https://api.geoportail.lu/geocoder/reverseGeocode';\n\nexport type ReverseGeocodeState =\n | { status: 'idle'; address: null; error: null }\n | { status: 'loading'; address: null; error: null }\n | { status: 'success'; address: Address; error: null }\n | { status: 'error'; address: null; error: Error };\n\n/**\n * Hook for reverse geocoding: convert a WGS84 lat/lon to a Luxembourg address.\n *\n * Uses the Geoportail REST reverse geocode endpoint — no API key required.\n *\n * @example\n * const { state, lookup } = useReverseGeocode();\n * // ...\n * lookup({ lat: 49.6116, lon: 6.1319 });\n * if (state.status === 'success') console.log(state.address.label);\n */\nexport function useReverseGeocode() {\n const [state, setState] = useState<ReverseGeocodeState>({\n status: 'idle',\n address: null,\n error: null,\n });\n\n const abortRef = useRef<AbortController | null>(null);\n\n useEffect(() => () => { abortRef.current?.abort(); }, []);\n\n const lookup = useCallback(async (position: LatLon) => {\n // Cancel any in-flight request\n abortRef.current?.abort();\n const controller = new AbortController();\n abortRef.current = controller;\n\n setState({ status: 'loading', address: null, error: null });\n\n try {\n const { easting, northing } = latLonToLuref(position.lat, position.lon);\n\n const url = new URL(REVERSE_GEOCODE_URL);\n url.searchParams.set('easting', String(easting));\n url.searchParams.set('northing', String(northing));\n\n const res = await fetch(url.toString(), { signal: controller.signal });\n\n if (!res.ok) {\n throw new Error(`Reverse geocode request failed: ${res.status} ${res.statusText}`);\n }\n\n const data = (await res.json()) as {\n results?: Array<{\n easting: number;\n northing: number;\n name?: string;\n distance?: number;\n }>;\n };\n\n const first = data.results?.[0];\n if (!first) {\n throw new Error('No results returned for this position');\n }\n\n setState({\n status: 'success',\n address: {\n label: first.name ?? '',\n distance: first.distance ?? 0,\n easting: first.easting,\n northing: first.northing,\n },\n error: null,\n });\n } catch (err: unknown) {\n if (err instanceof DOMException && err.name === 'AbortError') return;\n setState({\n status: 'error',\n address: null,\n error: err instanceof Error ? err : new Error(String(err)),\n });\n }\n }, []);\n\n const reset = useCallback(() => {\n abortRef.current?.abort();\n setState({ status: 'idle', address: null, error: null });\n }, []);\n\n return { state, lookup, reset };\n}\n","import { useState, useEffect, useCallback, useRef } from 'react';\nimport { lurefToLatLon } from '../utils/coordinates';\nimport type { GeocodeQuery, LatLon } from '../types';\n\nconst GEOCODE_URL = 'https://apiv3.geoportail.lu/geocode/search';\n\nexport interface GeocodeResultItem {\n latLon: LatLon;\n easting: number;\n northing: number;\n accuracy: number;\n street?: string;\n num?: string;\n zip?: string;\n locality?: string;\n}\n\nexport type GeocodeState =\n | { status: 'idle'; results: null; error: null }\n | { status: 'loading'; results: null; error: null }\n | { status: 'success'; results: GeocodeResultItem[]; error: null }\n | { status: 'error'; results: null; error: Error };\n\n/**\n * Hook for forward geocoding: search for a Luxembourg address and get coordinates.\n *\n * @example\n * const { state, search } = useGeocode();\n * search({ queryString: '1 rue du Fort Thüngen, Luxembourg' });\n * if (state.status === 'success') {\n * const { lat, lon } = state.results[0].latLon;\n * }\n */\nexport function useGeocode() {\n const [state, setState] = useState<GeocodeState>({\n status: 'idle',\n results: null,\n error: null,\n });\n\n const abortRef = useRef<AbortController | null>(null);\n\n useEffect(() => () => { abortRef.current?.abort(); }, []);\n\n const search = useCallback(async (query: GeocodeQuery) => {\n abortRef.current?.abort();\n const controller = new AbortController();\n abortRef.current = controller;\n\n setState({ status: 'loading', results: null, error: null });\n\n try {\n const url = new URL(GEOCODE_URL);\n\n if (query.queryString) {\n url.searchParams.set('queryString', query.queryString);\n } else {\n if (query.num) url.searchParams.set('num', query.num);\n if (query.street) url.searchParams.set('street', query.street);\n if (query.zip) url.searchParams.set('zip', query.zip);\n if (query.locality) url.searchParams.set('locality', query.locality);\n }\n\n const res = await fetch(url.toString(), { signal: controller.signal });\n\n if (!res.ok) {\n throw new Error(`Geocode request failed: ${res.status} ${res.statusText}`);\n }\n\n const data = (await res.json()) as {\n results?: Array<{\n easting: number;\n northing: number;\n accuracy?: number;\n AddressDetails?: {\n street?: string;\n number?: string;\n zip?: string;\n locality?: string;\n };\n }>;\n };\n\n const results: GeocodeResultItem[] = (data.results ?? []).map((r) => ({\n latLon: lurefToLatLon(r.easting, r.northing),\n easting: r.easting,\n northing: r.northing,\n accuracy: r.accuracy ?? 0,\n street: r.AddressDetails?.street,\n num: r.AddressDetails?.number,\n zip: r.AddressDetails?.zip,\n locality: r.AddressDetails?.locality,\n }));\n\n setState({ status: 'success', results, error: null });\n } catch (err: unknown) {\n if (err instanceof DOMException && err.name === 'AbortError') return;\n setState({\n status: 'error',\n results: null,\n error: err instanceof Error ? err : new Error(String(err)),\n });\n }\n }, []);\n\n const reset = useCallback(() => {\n abortRef.current?.abort();\n setState({ status: 'idle', results: null, error: null });\n }, []);\n\n return { state, search, reset };\n}\n"],"names":["LUX_BASE_URL","LUX_PROTOCOL","LUX_I18N_URL","LUX_STYLESHEET_URL","LUX_VENDOR_URL","LUX_API_URL","LUX_STYLESHEET_ID","LUX_VENDOR_SCRIPT_ID","LUX_API_SCRIPT_ID","ELEMENT_STATUS_ATTRIBUTE","loadPromise","loadLuxApi","loadLuxApiInternal","error","pollForLux","resolve","reject","attempts","check","configureLux","loadStylesheetOnce","loadScriptOnce","waitForLux","lux","id","src","existing","waitForElementLoad","script","attachLoadHandlers","href","link","element","resourceUrl","kind","status","onLoad","onError","handleLoad","cleanup","handleError","useLuxApi","state","setState","useState","useEffect","cancelled","err","FE","FN","LON0","LAT0","SCALE","A","F","B","E2","DX","DY","DZ","degToRad","d","radToDeg","r","wgs84ToEd50","lat","lon","latR","lonR","sinLat","cosLat","sinLon","cosLon","aWgs","fWgs","bWgs","e2Wgs","da","df","N","dLat","dLon","ed50ToWgs84","M","tmForward","lon0R","lat0R","tanLat","T","C","dl","XX","meridianArc","M0","easting","northing","tmInverse","x","y","mu","e1","phi1","sinPhi1","cosPhi1","tanPhi1","N1","T1","C1","R1","D","e2","e4","e6","latLonToLuref","ed50","lurefToLatLon","DEFAULT_CLICK_SOURCE_PROJECTION","WGS84_PROJECTION","LUXEMBOURG_CITY","DEFAULT_BG_LAYER","GeoportailMap","forwardRef","center","zoom","bgLayer","markerMode","markerPosition","onMarkerPlace","className","style","layers","ref","luxApi","mapContainerRef","useRef","mapRef","markerLayerRef","clickListenerRef","onMarkerPlaceRef","mapInstance","map","clearMarker","initialPos","placeMarker","handler","args","evt","latLon","convertMapClickCoordinateToLatLon","_a","useImperativeHandle","coords","z","jsx","jsxs","position","layerRef","ol","overlay","el","PIN_SVG","_map","coordinate","transform","sourceProjection","_e","_d","_c","_b","REVERSE_GEOCODE_URL","useReverseGeocode","abortRef","lookup","useCallback","controller","url","res","first","reset","GEOCODE_URL","useGeocode","search","query","results"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
- (function(b,x){typeof exports=="object"&&typeof module<"u"?x(exports,require("react/jsx-runtime"),require("react")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react"],x):(b=typeof globalThis<"u"?globalThis:b||self,x(b.ReactGeoportail={},b.jsxRuntime,b.React))})(this,function(b,x,w){"use strict";const Q="https://apiv3.geoportail.lu/",tt="https",nt="https://apiv3.geoportail.lu/static-ngeo/build/fr.json",et="https://apiv3.geoportail.lu/static-ngeo/build/apiv3.css",st="https://apiv3.geoportail.lu/static-ngeo/build/vendor.js",ot="https://apiv3.geoportail.lu/static-ngeo/build/apiv3.js",rt="geoportail-apiv3-css",at="geoportail-apiv3-vendor",ct="geoportail-apiv3-script",_="data-geoportail-status";let T=null;function X(){return T||(typeof window>"u"||typeof document>"u"?Promise.reject(new Error("loadLuxApi must be called in a browser environment")):(T=lt().catch(n=>{throw T=null,n instanceof Error?n:new Error(String(n))}),T))}function it(n,e){let i=0;const o=()=>{if(window.lux){n();return}if(i++>=100){T=null,e(new Error("Timed out waiting for window.lux to be defined"));return}setTimeout(o,50)};o()}async function lt(){if(window.lux){N(window.lux);return}await dt(rt,et),await $(at,st),await $(ct,ot),await ut(),N(window.lux)}function ut(){return new Promise((n,e)=>{it(n,e)})}function N(n){n.setBaseUrl(Q,tt),n.setI18nUrl(nt)}function $(n,e){const s=document.getElementById(n);return s?B(s,e,"script"):new Promise((i,o)=>{const t=document.createElement("script");t.id=n,t.src=e,t.async=!1,t.setAttribute(_,"loading"),P(t,()=>i(),()=>o(new Error(`Failed to load Geoportail script from ${e}`)),"script"),document.head.appendChild(t)})}function dt(n,e){const s=document.getElementById(n);return s?B(s,e,"stylesheet"):new Promise((i,o)=>{const t=document.createElement("link");t.id=n,t.rel="stylesheet",t.href=e,t.setAttribute(_,"loading"),P(t,()=>i(),()=>o(new Error(`Failed to load Geoportail stylesheet from ${e}`)),"stylesheet"),document.head.appendChild(t)})}function B(n,e,s){const i=n.getAttribute(_);return i==="loaded"?Promise.resolve():i==="error"?(n.remove(),Promise.reject(new Error(`Failed to load Geoportail ${s} from ${e}`))):new Promise((o,t)=>{P(n,()=>o(),()=>t(new Error(`Failed to load Geoportail ${s} from ${e}`)),s)})}function P(n,e,s,i){const o=()=>{n.setAttribute(_,"loaded"),f(),e()},t=()=>{n.setAttribute(_,"error"),f(),n.remove(),s()},f=()=>{n.removeEventListener("load",o),n.removeEventListener("error",t)};return n.addEventListener("load",o,{once:!0}),n.addEventListener("error",t,{once:!0}),i==="stylesheet"?n.sheet&&o():n.dataset.geoportailStatus==="loaded"&&o(),f}function z(){const[n,e]=w.useState({status:"loading",lux:null,error:null});return w.useEffect(()=>{let s=!1;return X().then(()=>{s||e({status:"ready",lux:window.lux,error:null})}).catch(i=>{s||e({status:"error",lux:null,error:i instanceof Error?i:new Error(String(i))})}),()=>{s=!0}},[]),n}const W=8e4,k=1e5,V=6.16666666666667,H=49.8333333333333,I=1,M=6378388,D=1/297,O=M*(1-D),E=1-O*O/(M*M),U=-87,G=-98,Y=-121;function R(n){return n*Math.PI/180}function A(n){return n*180/Math.PI}function ft(n,e){const s=R(n),i=R(e),o=Math.sin(s),t=Math.cos(s),f=Math.sin(i),h=Math.cos(i),r=6378137,c=1/298.257223563,p=r*(1-c),l=1-p*p/(r*r),d=M-r,a=D-c,g=r/Math.sqrt(1-l*o*o),L=1/(r*(1-l)/Math.pow(1-l*o*o,1.5))*(g*(l/(1-l))*o*t*(d/r)+(g/r+1)*o*t*a*(r/p)-(U*o*h+G*o*f-Y*t)),m=1/(g*t)*(-U*f+G*h);return{lat:n+A(L),lon:e+A(m)}}function ht(n,e){const s=R(n),i=R(e),o=Math.sin(s),t=Math.cos(s),f=Math.sin(i),h=Math.cos(i),r=M/Math.sqrt(1-E*o*o),c=M*(1-E)/Math.pow(1-E*o*o,1.5),p=6378137-M,d=1/298.257223563-D,a=1/c*(r*(E/(1-E))*o*t*(p/M)+(r/M+1)*o*t*d*(M/O)+(U*o*h+G*o*f-Y*t)),g=1/(r*t)*(U*f-G*h);return{lat:n+A(a),lon:e+A(g)}}function pt(n,e){const s=R(n),i=R(e),o=R(V),t=R(H),f=Math.sin(s),h=Math.cos(s),r=Math.tan(s),c=M/Math.sqrt(1-E*f*f),p=r*r,l=E/(1-E)*h*h,d=i-o,a=h*d,g=j(s),v=j(t),L=W+I*c*(a+a*a*a*(1-p+l)/6+a*a*a*a*a*(5-18*p+p*p+72*l)/120),m=k+I*(g-v+c*r*(a*a/2+a*a*a*a*(5-p+9*l+4*l*l)/24+a*a*a*a*a*a*(61-58*p+p*p+600*l)/720));return{easting:L,northing:m}}function gt(n,e){const s=n-W,i=e-k,o=R(H),t=R(V),r=(j(o)+i/I)/(M*(1-E/4-3*E*E/64)),c=(1-Math.sqrt(1-E))/(1+Math.sqrt(1-E)),p=r+(3*c/2-27*c*c*c/32)*Math.sin(2*r)+(21*c*c/16-55*c*c*c*c/32)*Math.sin(4*r)+151*c*c*c/96*Math.sin(6*r),l=Math.sin(p),d=Math.cos(p),a=Math.tan(p),g=M/Math.sqrt(1-E*l*l),v=a*a,L=E/(1-E)*d*d,m=M*(1-E)/Math.pow(1-E*l*l,1.5),u=s/(g*I),y=p-g*a/m*(u*u/2-u*u*u*u*(5+3*v+10*L-4*L*L)/24+u*u*u*u*u*u*(61+90*v+298*L+45*v*v)/720),S=t+(u-u*u*u*(1+2*v+L)/6+u*u*u*u*u*(5-2*L+28*v-3*L*L)/120)/d;return{lat:A(y),lon:A(S)}}function j(n){const e=E,s=e*e,i=s*e;return M*((1-e/4-3*s/64-5*i/256)*n-(3*e/8+3*s/32+45*i/1024)*Math.sin(2*n)+(15*s/256+45*i/1024)*Math.sin(4*n)-35*i/3072*Math.sin(6*n))}function C(n,e){const s=ft(n,e);return pt(s.lat,s.lon)}function F(n,e){const s=gt(n,e);return ht(s.lat,s.lon)}const wt={lat:49.6116,lon:6.1319},Lt="basemap_2015_global",Et=w.forwardRef(function({center:e=wt,zoom:s=12,bgLayer:i=Lt,markerMode:o="none",markerPosition:t,onMarkerPlace:f,className:h,style:r,layers:c},p){const l=z(),d=w.useRef(null),a=w.useRef(null),g=w.useRef(null),v=w.useRef(null),L=w.useRef(f);return L.current=f,w.useEffect(()=>{if(l.status!=="ready"||!d.current)return;const m=l.lux,{easting:u,northing:y}=C(e.lat,e.lon),S=new m.Map({target:d.current,bgLayer:i,zoom:s,position:[u,y],...c&&c.length>0?{layers:c,layerOpacities:c.map(()=>1)}:{}});return a.current=S,()=>{a.current=null,g.current=null,v.current=null}},[l.status]),w.useEffect(()=>{const m=a.current;if(!m||l.status!=="ready")return;if(v.current&&(m.un("singleclick",v.current),v.current=null),o==="none"){mt(m,g);return}const u=t??(o==="fixed"?e:void 0);if(u&&q(m,u,g),o==="click"){const y=(...S)=>{var K;const Z=S[0];if(!Z.coordinate)return;const[yt,St]=Z.coordinate,J=F(yt,St);q(m,J,g),(K=L.current)==null||K.call(L,J)};v.current=y,m.on("singleclick",y)}},[l.status,o,t==null?void 0:t.lat,t==null?void 0:t.lon,e.lat,e.lon]),w.useImperativeHandle(p,()=>({getLuxMap:()=>a.current,setCenter(m){const u=a.current;if(!u)return;const{easting:y,northing:S}=C(m.lat,m.lon);u.getView().setCenter([y,S])},setZoom(m){var u;(u=a.current)==null||u.getView().setZoom(m)}})),l.status==="error"?x.jsx("div",{className:h,style:{display:"flex",alignItems:"center",justifyContent:"center",background:"#f5f5f5",...r},children:x.jsxs("span",{style:{color:"#c00"},children:["Failed to load Geoportail API: ",l.error.message]})}):x.jsxs("div",{style:{position:"relative",...r},className:h,children:[l.status==="loading"&&x.jsx("div",{style:{position:"absolute",inset:0,display:"flex",alignItems:"center",justifyContent:"center",background:"rgba(255,255,255,0.7)",zIndex:10},children:x.jsx("span",{children:"Loading map…"})}),x.jsx("div",{ref:d,style:{width:"100%",height:"100%"}})]})});function q(n,e,s){const i=window.ol;if(!i)return;const{easting:o,northing:t}=C(e.lat,e.lon);if(s.current){s.current.setPosition([o,t]);return}const f=document.createElement("div");f.innerHTML=vt,f.style.cssText="cursor:pointer;transform:translate(-50%,-100%);line-height:0;";const h=new i.Overlay({element:f,positioning:"bottom-center",stopEvent:!1});h.setPosition([o,t]),n.addOverlay(h),s.current=h}function mt(n,e){!e.current||!window.ol||(e.current.setPosition(void 0),e.current=null)}const vt=`<svg xmlns="http://www.w3.org/2000/svg" width="30" height="40" viewBox="0 0 30 40">
1
+ (function(R,b){typeof exports=="object"&&typeof module<"u"?b(exports,require("react/jsx-runtime"),require("react")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react"],b):(R=typeof globalThis<"u"?globalThis:R||self,b(R.ReactGeoportail={},R.jsxRuntime,R.React))})(this,function(R,b,L){"use strict";const Q="https://apiv3.geoportail.lu/",tt="https",nt="https://apiv3.geoportail.lu/static-ngeo/build/fr.json",et="https://apiv3.geoportail.lu/static-ngeo/build/apiv3.css",ot="https://apiv3.geoportail.lu/static-ngeo/build/vendor.js",st="https://apiv3.geoportail.lu/static-ngeo/build/apiv3.js",rt="geoportail-apiv3-css",ct="geoportail-apiv3-vendor",at="geoportail-apiv3-script",_="data-geoportail-status";let y=null;function N(){return y||(typeof window>"u"||typeof document>"u"?Promise.reject(new Error("loadLuxApi must be called in a browser environment")):(y=lt().catch(n=>{throw y=null,n instanceof Error?n:new Error(String(n))}),y))}function it(n,e){let i=0;const s=()=>{if(window.lux){n();return}if(i++>=100){y=null,e(new Error("Timed out waiting for window.lux to be defined"));return}setTimeout(s,50)};s()}async function lt(){if(window.lux){X(window.lux);return}await dt(rt,et),await $(ct,ot),await $(at,st),await ut(),X(window.lux)}function ut(){return new Promise((n,e)=>{it(n,e)})}function X(n){n.setBaseUrl(Q,tt),n.setI18nUrl(nt)}function $(n,e){const o=document.getElementById(n);return o?B(o,e,"script"):new Promise((i,s)=>{const t=document.createElement("script");t.id=n,t.src=e,t.async=!1,t.setAttribute(_,"loading"),O(t,()=>i(),()=>s(new Error(`Failed to load Geoportail script from ${e}`)),"script"),document.head.appendChild(t)})}function dt(n,e){const o=document.getElementById(n);return o?B(o,e,"stylesheet"):new Promise((i,s)=>{const t=document.createElement("link");t.id=n,t.rel="stylesheet",t.href=e,t.setAttribute(_,"loading"),O(t,()=>i(),()=>s(new Error(`Failed to load Geoportail stylesheet from ${e}`)),"stylesheet"),document.head.appendChild(t)})}function B(n,e,o){const i=n.getAttribute(_);return i==="loaded"?Promise.resolve():i==="error"?(n.remove(),Promise.reject(new Error(`Failed to load Geoportail ${o} from ${e}`))):new Promise((s,t)=>{O(n,()=>s(),()=>t(new Error(`Failed to load Geoportail ${o} from ${e}`)),o)})}function O(n,e,o,i){const s=()=>{n.setAttribute(_,"loaded"),h(),e()},t=()=>{n.setAttribute(_,"error"),h(),n.remove(),o()},h=()=>{n.removeEventListener("load",s),n.removeEventListener("error",t)};return n.addEventListener("load",s,{once:!0}),n.addEventListener("error",t,{once:!0}),i==="stylesheet"?n.sheet&&s():n.dataset.geoportailStatus==="loaded"&&s(),h}function W(){const[n,e]=L.useState({status:"loading",lux:null,error:null});return L.useEffect(()=>{let o=!1;return N().then(()=>{o||e({status:"ready",lux:window.lux,error:null})}).catch(i=>{o||e({status:"error",lux:null,error:i instanceof Error?i:new Error(String(i))})}),()=>{o=!0}},[]),n}const k=8e4,z=1e5,V=6.16666666666667,H=49.8333333333333,I=1,M=6378388,G=1/297,D=M*(1-G),m=1-D*D/(M*M),P=-87,U=-98,Y=-121;function S(n){return n*Math.PI/180}function A(n){return n*180/Math.PI}function ft(n,e){const o=S(n),i=S(e),s=Math.sin(o),t=Math.cos(o),h=Math.sin(i),p=Math.cos(i),r=6378137,c=1/298.257223563,f=r*(1-c),l=1-f*f/(r*r),d=M-r,a=G-c,g=r/Math.sqrt(1-l*s*s),w=1/(r*(1-l)/Math.pow(1-l*s*s,1.5))*(g*(l/(1-l))*s*t*(d/r)+(g/r+1)*s*t*a*(r/f)-(P*s*p+U*s*h-Y*t)),E=1/(g*t)*(-P*h+U*p);return{lat:n+A(w),lon:e+A(E)}}function ht(n,e){const o=S(n),i=S(e),s=Math.sin(o),t=Math.cos(o),h=Math.sin(i),p=Math.cos(i),r=M/Math.sqrt(1-m*s*s),c=M*(1-m)/Math.pow(1-m*s*s,1.5),f=6378137-M,d=1/298.257223563-G,a=1/c*(r*(m/(1-m))*s*t*(f/M)+(r/M+1)*s*t*d*(M/D)+(P*s*p+U*s*h-Y*t)),g=1/(r*t)*(P*h-U*p);return{lat:n+A(a),lon:e+A(g)}}function pt(n,e){const o=S(n),i=S(e),s=S(V),t=S(H),h=Math.sin(o),p=Math.cos(o),r=Math.tan(o),c=M/Math.sqrt(1-m*h*h),f=r*r,l=m/(1-m)*p*p,d=i-s,a=p*d,g=j(o),v=j(t),w=k+I*c*(a+a*a*a*(1-f+l)/6+a*a*a*a*a*(5-18*f+f*f+72*l)/120),E=z+I*(g-v+c*r*(a*a/2+a*a*a*a*(5-f+9*l+4*l*l)/24+a*a*a*a*a*a*(61-58*f+f*f+600*l)/720));return{easting:w,northing:E}}function gt(n,e){const o=n-k,i=e-z,s=S(H),t=S(V),r=(j(s)+i/I)/(M*(1-m/4-3*m*m/64)),c=(1-Math.sqrt(1-m))/(1+Math.sqrt(1-m)),f=r+(3*c/2-27*c*c*c/32)*Math.sin(2*r)+(21*c*c/16-55*c*c*c*c/32)*Math.sin(4*r)+151*c*c*c/96*Math.sin(6*r),l=Math.sin(f),d=Math.cos(f),a=Math.tan(f),g=M/Math.sqrt(1-m*l*l),v=a*a,w=m/(1-m)*d*d,E=M*(1-m)/Math.pow(1-m*l*l,1.5),u=o/(g*I),T=f-g*a/E*(u*u/2-u*u*u*u*(5+3*v+10*w-4*w*w)/24+u*u*u*u*u*u*(61+90*v+298*w+45*v*v)/720),x=t+(u-u*u*u*(1+2*v+w)/6+u*u*u*u*u*(5-2*w+28*v-3*w*w)/120)/d;return{lat:A(T),lon:A(x)}}function j(n){const e=m,o=e*e,i=o*e;return M*((1-e/4-3*o/64-5*i/256)*n-(3*e/8+3*o/32+45*i/1024)*Math.sin(2*n)+(15*o/256+45*i/1024)*Math.sin(4*n)-35*i/3072*Math.sin(6*n))}function C(n,e){const o=ft(n,e);return pt(o.lat,o.lon)}function F(n,e){const o=gt(n,e);return ht(o.lat,o.lon)}const Lt="EPSG:3857",wt="EPSG:4326",Et={lat:49.6116,lon:6.1319},mt="basemap_2015_global",vt=L.forwardRef(function({center:e=Et,zoom:o=12,bgLayer:i=mt,markerMode:s="none",markerPosition:t,onMarkerPlace:h,className:p,style:r,layers:c},f){const l=W(),d=L.useRef(null),a=L.useRef(null),g=L.useRef(null),v=L.useRef(null),w=L.useRef(h);return w.current=h,L.useEffect(()=>{if(l.status!=="ready"||!d.current)return;const E=l.lux,{easting:u,northing:T}=C(e.lat,e.lon),x=new E.Map({target:d.current,bgLayer:i,zoom:o,position:[u,T],...c&&c.length>0?{layers:c,layerOpacities:c.map(()=>1)}:{}});return a.current=x,()=>{a.current=null,g.current=null,v.current=null}},[l.status]),L.useEffect(()=>{const E=a.current;if(!E||l.status!=="ready")return;if(v.current&&(E.un("singleclick",v.current),v.current=null),s==="none"){Mt(E,g);return}const u=t??(s==="fixed"?e:void 0);if(u&&q(E,u,g),s==="click"){const T=(...x)=>{var K;const Z=x[0];if(!Z.coordinate)return;const J=bt(E,Z.coordinate);q(E,J,g),(K=w.current)==null||K.call(w,J)};v.current=T,E.on("singleclick",T)}},[l.status,s,t==null?void 0:t.lat,t==null?void 0:t.lon,e.lat,e.lon]),L.useImperativeHandle(f,()=>({getLuxMap:()=>a.current,setCenter(E){const u=a.current;if(!u)return;const{easting:T,northing:x}=C(E.lat,E.lon);u.getView().setCenter([T,x])},setZoom(E){var u;(u=a.current)==null||u.getView().setZoom(E)}})),l.status==="error"?b.jsx("div",{className:p,style:{display:"flex",alignItems:"center",justifyContent:"center",background:"#f5f5f5",...r},children:b.jsxs("span",{style:{color:"#c00"},children:["Failed to load Geoportail API: ",l.error.message]})}):b.jsxs("div",{style:{position:"relative",...r},className:p,children:[l.status==="loading"&&b.jsx("div",{style:{position:"absolute",inset:0,display:"flex",alignItems:"center",justifyContent:"center",background:"rgba(255,255,255,0.7)",zIndex:10},children:b.jsx("span",{children:"Loading map…"})}),b.jsx("div",{ref:d,style:{width:"100%",height:"100%"}})]})});function q(n,e,o){const i=window.ol;if(!i)return;const{easting:s,northing:t}=C(e.lat,e.lon);if(o.current){o.current.setPosition([s,t]);return}const h=document.createElement("div");h.innerHTML=Rt,h.style.cssText="cursor:pointer;transform:translate(-50%,-100%);line-height:0;";const p=new i.Overlay({element:h,positioning:"bottom-center",stopEvent:!1});p.setPosition([s,t]),n.addOverlay(p),o.current=p}function Mt(n,e){!e.current||!window.ol||(e.current.setPosition(void 0),e.current=null)}const Rt=`<svg xmlns="http://www.w3.org/2000/svg" width="30" height="40" viewBox="0 0 30 40">
2
2
  <path d="M15 0C7.268 0 1 6.268 1 14c0 10.5 14 26 14 26S29 24.5 29 14C29 6.268 22.732 0 15 0z"
3
3
  fill="#e53935" stroke="#b71c1c" stroke-width="1.5"/>
4
4
  <circle cx="15" cy="14" r="5" fill="white"/>
5
- </svg>`,Mt="https://api.geoportail.lu/geocoder/reverseGeocode";function bt(){const[n,e]=w.useState({status:"idle",address:null,error:null}),s=w.useRef(null);w.useEffect(()=>()=>{var t;(t=s.current)==null||t.abort()},[]);const i=w.useCallback(async t=>{var h,r;(h=s.current)==null||h.abort();const f=new AbortController;s.current=f,e({status:"loading",address:null,error:null});try{const{easting:c,northing:p}=C(t.lat,t.lon),l=new URL(Mt);l.searchParams.set("easting",String(c)),l.searchParams.set("northing",String(p));const d=await fetch(l.toString(),{signal:f.signal});if(!d.ok)throw new Error(`Reverse geocode request failed: ${d.status} ${d.statusText}`);const g=(r=(await d.json()).results)==null?void 0:r[0];if(!g)throw new Error("No results returned for this position");e({status:"success",address:{label:g.name??"",distance:g.distance??0,easting:g.easting,northing:g.northing},error:null})}catch(c){if(c instanceof DOMException&&c.name==="AbortError")return;e({status:"error",address:null,error:c instanceof Error?c:new Error(String(c))})}},[]),o=w.useCallback(()=>{var t;(t=s.current)==null||t.abort(),e({status:"idle",address:null,error:null})},[]);return{state:n,lookup:i,reset:o}}const xt="https://apiv3.geoportail.lu/geocode/search";function Rt(){const[n,e]=w.useState({status:"idle",results:null,error:null}),s=w.useRef(null);w.useEffect(()=>()=>{var t;(t=s.current)==null||t.abort()},[]);const i=w.useCallback(async t=>{var h;(h=s.current)==null||h.abort();const f=new AbortController;s.current=f,e({status:"loading",results:null,error:null});try{const r=new URL(xt);t.queryString?r.searchParams.set("queryString",t.queryString):(t.num&&r.searchParams.set("num",t.num),t.street&&r.searchParams.set("street",t.street),t.zip&&r.searchParams.set("zip",t.zip),t.locality&&r.searchParams.set("locality",t.locality));const c=await fetch(r.toString(),{signal:f.signal});if(!c.ok)throw new Error(`Geocode request failed: ${c.status} ${c.statusText}`);const l=((await c.json()).results??[]).map(d=>{var a,g,v,L;return{latLon:F(d.easting,d.northing),easting:d.easting,northing:d.northing,accuracy:d.accuracy??0,street:(a=d.AddressDetails)==null?void 0:a.street,num:(g=d.AddressDetails)==null?void 0:g.number,zip:(v=d.AddressDetails)==null?void 0:v.zip,locality:(L=d.AddressDetails)==null?void 0:L.locality}});e({status:"success",results:l,error:null})}catch(r){if(r instanceof DOMException&&r.name==="AbortError")return;e({status:"error",results:null,error:r instanceof Error?r:new Error(String(r))})}},[]),o=w.useCallback(()=>{var t;(t=s.current)==null||t.abort(),e({status:"idle",results:null,error:null})},[]);return{state:n,search:i,reset:o}}b.GeoportailMap=Et,b.latLonToLuref=C,b.loadLuxApi=X,b.lurefToLatLon=F,b.useGeocode=Rt,b.useLuxApi=z,b.useReverseGeocode=bt,Object.defineProperty(b,Symbol.toStringTag,{value:"Module"})});
5
+ </svg>`;function bt(n,e){var p,r,c,f,l;const o=window.ol,i=(p=o==null?void 0:o.proj)==null?void 0:p.transform;if(!i){const[d,a]=e;return F(d,a)}const s=((l=(f=(c=(r=n.getView()).getProjection)==null?void 0:c.call(r))==null?void 0:f.getCode)==null?void 0:l.call(f))??Lt,[t,h]=i(e,s,wt);return{lat:h,lon:t}}const St="https://api.geoportail.lu/geocoder/reverseGeocode";function Tt(){const[n,e]=L.useState({status:"idle",address:null,error:null}),o=L.useRef(null);L.useEffect(()=>()=>{var t;(t=o.current)==null||t.abort()},[]);const i=L.useCallback(async t=>{var p,r;(p=o.current)==null||p.abort();const h=new AbortController;o.current=h,e({status:"loading",address:null,error:null});try{const{easting:c,northing:f}=C(t.lat,t.lon),l=new URL(St);l.searchParams.set("easting",String(c)),l.searchParams.set("northing",String(f));const d=await fetch(l.toString(),{signal:h.signal});if(!d.ok)throw new Error(`Reverse geocode request failed: ${d.status} ${d.statusText}`);const g=(r=(await d.json()).results)==null?void 0:r[0];if(!g)throw new Error("No results returned for this position");e({status:"success",address:{label:g.name??"",distance:g.distance??0,easting:g.easting,northing:g.northing},error:null})}catch(c){if(c instanceof DOMException&&c.name==="AbortError")return;e({status:"error",address:null,error:c instanceof Error?c:new Error(String(c))})}},[]),s=L.useCallback(()=>{var t;(t=o.current)==null||t.abort(),e({status:"idle",address:null,error:null})},[]);return{state:n,lookup:i,reset:s}}const xt="https://apiv3.geoportail.lu/geocode/search";function yt(){const[n,e]=L.useState({status:"idle",results:null,error:null}),o=L.useRef(null);L.useEffect(()=>()=>{var t;(t=o.current)==null||t.abort()},[]);const i=L.useCallback(async t=>{var p;(p=o.current)==null||p.abort();const h=new AbortController;o.current=h,e({status:"loading",results:null,error:null});try{const r=new URL(xt);t.queryString?r.searchParams.set("queryString",t.queryString):(t.num&&r.searchParams.set("num",t.num),t.street&&r.searchParams.set("street",t.street),t.zip&&r.searchParams.set("zip",t.zip),t.locality&&r.searchParams.set("locality",t.locality));const c=await fetch(r.toString(),{signal:h.signal});if(!c.ok)throw new Error(`Geocode request failed: ${c.status} ${c.statusText}`);const l=((await c.json()).results??[]).map(d=>{var a,g,v,w;return{latLon:F(d.easting,d.northing),easting:d.easting,northing:d.northing,accuracy:d.accuracy??0,street:(a=d.AddressDetails)==null?void 0:a.street,num:(g=d.AddressDetails)==null?void 0:g.number,zip:(v=d.AddressDetails)==null?void 0:v.zip,locality:(w=d.AddressDetails)==null?void 0:w.locality}});e({status:"success",results:l,error:null})}catch(r){if(r instanceof DOMException&&r.name==="AbortError")return;e({status:"error",results:null,error:r instanceof Error?r:new Error(String(r))})}},[]),s=L.useCallback(()=>{var t;(t=o.current)==null||t.abort(),e({status:"idle",results:null,error:null})},[]);return{state:n,search:i,reset:s}}R.GeoportailMap=vt,R.latLonToLuref=C,R.loadLuxApi=N,R.lurefToLatLon=F,R.useGeocode=yt,R.useLuxApi=W,R.useReverseGeocode=Tt,Object.defineProperty(R,Symbol.toStringTag,{value:"Module"})});
6
6
  //# sourceMappingURL=react-geoportail.umd.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"react-geoportail.umd.cjs","sources":["../src/utils/loader.ts","../src/hooks/useLuxApi.ts","../src/utils/coordinates.ts","../src/components/GeoportailMap.tsx","../src/hooks/useReverseGeocode.ts","../src/hooks/useGeocode.ts"],"sourcesContent":["/**\n * Dynamically injects the Geoportail v3 assets and resolves when\n * the global `lux` namespace is available.\n */\n\nconst LUX_BASE_URL = 'https://apiv3.geoportail.lu/';\nconst LUX_PROTOCOL = 'https';\nconst LUX_I18N_URL = 'https://apiv3.geoportail.lu/static-ngeo/build/fr.json';\nconst LUX_STYLESHEET_URL = 'https://apiv3.geoportail.lu/static-ngeo/build/apiv3.css';\nconst LUX_VENDOR_URL = 'https://apiv3.geoportail.lu/static-ngeo/build/vendor.js';\nconst LUX_API_URL = 'https://apiv3.geoportail.lu/static-ngeo/build/apiv3.js';\n\nconst LUX_STYLESHEET_ID = 'geoportail-apiv3-css';\nconst LUX_VENDOR_SCRIPT_ID = 'geoportail-apiv3-vendor';\nconst LUX_API_SCRIPT_ID = 'geoportail-apiv3-script';\n\nconst ELEMENT_STATUS_ATTRIBUTE = 'data-geoportail-status';\n\nlet loadPromise: Promise<void> | null = null;\n\n/**\n * Loads the Geoportail API assets exactly once.\n * Safe to call multiple times — subsequent calls return the same promise.\n */\nexport function loadLuxApi(): Promise<void> {\n if (loadPromise) return loadPromise;\n\n if (typeof window === 'undefined' || typeof document === 'undefined') {\n return Promise.reject(new Error('loadLuxApi must be called in a browser environment'));\n }\n\n loadPromise = loadLuxApiInternal().catch((error: unknown) => {\n loadPromise = null;\n throw error instanceof Error ? error : new Error(String(error));\n });\n\n return loadPromise;\n}\n\n/**\n * The lux API may initialise asynchronously after the scripts load.\n * Poll until window.lux is defined (max ~5 s).\n */\nfunction pollForLux(resolve: () => void, reject: (err: Error) => void): void {\n const maxAttempts = 100;\n let attempts = 0;\n\n const check = () => {\n if (window.lux) {\n resolve();\n return;\n }\n if (attempts++ >= maxAttempts) {\n loadPromise = null;\n reject(new Error('Timed out waiting for window.lux to be defined'));\n return;\n }\n setTimeout(check, 50);\n };\n\n check();\n}\n\nasync function loadLuxApiInternal(): Promise<void> {\n if (window.lux) {\n configureLux(window.lux);\n return;\n }\n\n await loadStylesheetOnce(LUX_STYLESHEET_ID, LUX_STYLESHEET_URL);\n await loadScriptOnce(LUX_VENDOR_SCRIPT_ID, LUX_VENDOR_URL);\n await loadScriptOnce(LUX_API_SCRIPT_ID, LUX_API_URL);\n await waitForLux();\n configureLux(window.lux!);\n}\n\nfunction waitForLux(): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n pollForLux(resolve, reject);\n });\n}\n\nfunction configureLux(lux: NonNullable<Window['lux']>): void {\n lux.setBaseUrl(LUX_BASE_URL, LUX_PROTOCOL);\n lux.setI18nUrl(LUX_I18N_URL);\n}\n\nfunction loadScriptOnce(id: string, src: string): Promise<void> {\n const existing = document.getElementById(id) as HTMLScriptElement | null;\n if (existing) {\n return waitForElementLoad(existing, src, 'script');\n }\n\n return new Promise<void>((resolve, reject) => {\n const script = document.createElement('script');\n script.id = id;\n script.src = src;\n script.async = false;\n script.setAttribute(ELEMENT_STATUS_ATTRIBUTE, 'loading');\n\n const cleanup = attachLoadHandlers(\n script,\n () => resolve(),\n () => reject(new Error(`Failed to load Geoportail script from ${src}`)),\n 'script'\n );\n\n document.head.appendChild(script);\n void cleanup;\n });\n}\n\nfunction loadStylesheetOnce(id: string, href: string): Promise<void> {\n const existing = document.getElementById(id) as HTMLLinkElement | null;\n if (existing) {\n return waitForElementLoad(existing, href, 'stylesheet');\n }\n\n return new Promise<void>((resolve, reject) => {\n const link = document.createElement('link');\n link.id = id;\n link.rel = 'stylesheet';\n link.href = href;\n link.setAttribute(ELEMENT_STATUS_ATTRIBUTE, 'loading');\n\n const cleanup = attachLoadHandlers(\n link,\n () => resolve(),\n () => reject(new Error(`Failed to load Geoportail stylesheet from ${href}`)),\n 'stylesheet'\n );\n\n document.head.appendChild(link);\n void cleanup;\n });\n}\n\nfunction waitForElementLoad(\n element: HTMLScriptElement | HTMLLinkElement,\n resourceUrl: string,\n kind: 'script' | 'stylesheet'\n): Promise<void> {\n const status = element.getAttribute(ELEMENT_STATUS_ATTRIBUTE);\n\n if (status === 'loaded') {\n return Promise.resolve();\n }\n\n if (status === 'error') {\n element.remove();\n return Promise.reject(new Error(`Failed to load Geoportail ${kind} from ${resourceUrl}`));\n }\n\n return new Promise<void>((resolve, reject) => {\n const cleanup = attachLoadHandlers(\n element,\n () => resolve(),\n () => reject(new Error(`Failed to load Geoportail ${kind} from ${resourceUrl}`)),\n kind\n );\n\n void cleanup;\n });\n}\n\nfunction attachLoadHandlers(\n element: HTMLScriptElement | HTMLLinkElement,\n onLoad: () => void,\n onError: () => void,\n kind: 'script' | 'stylesheet'\n): () => void {\n const handleLoad = () => {\n element.setAttribute(ELEMENT_STATUS_ATTRIBUTE, 'loaded');\n cleanup();\n onLoad();\n };\n\n const handleError = () => {\n element.setAttribute(ELEMENT_STATUS_ATTRIBUTE, 'error');\n cleanup();\n element.remove();\n onError();\n };\n\n const cleanup = () => {\n element.removeEventListener('load', handleLoad);\n element.removeEventListener('error', handleError);\n };\n\n element.addEventListener('load', handleLoad, { once: true });\n element.addEventListener('error', handleError, { once: true });\n\n if (kind === 'stylesheet') {\n const link = element as HTMLLinkElement;\n if (link.sheet) {\n handleLoad();\n }\n } else {\n const script = element as HTMLScriptElement;\n if (script.dataset.geoportailStatus === 'loaded') {\n handleLoad();\n }\n }\n\n return cleanup;\n}\n","import { useState, useEffect } from 'react';\nimport { loadLuxApi } from '../utils/loader';\nimport type { LuxNamespace } from '../types/lux';\n\nexport type LuxApiState =\n | { status: 'loading'; lux: null; error: null }\n | { status: 'ready'; lux: LuxNamespace; error: null }\n | { status: 'error'; lux: null; error: Error };\n\n/**\n * Loads the Geoportail runtime assets and returns the `lux` namespace once ready.\n * Deduplicates the asset load — safe to call from multiple components.\n */\nexport function useLuxApi(): LuxApiState {\n const [state, setState] = useState<LuxApiState>({\n status: 'loading',\n lux: null,\n error: null,\n });\n\n useEffect(() => {\n let cancelled = false;\n\n loadLuxApi()\n .then(() => {\n if (!cancelled) {\n setState({ status: 'ready', lux: window.lux!, error: null });\n }\n })\n .catch((err: unknown) => {\n if (!cancelled) {\n setState({\n status: 'error',\n lux: null,\n error: err instanceof Error ? err : new Error(String(err)),\n });\n }\n });\n\n return () => {\n cancelled = true;\n };\n }, []);\n\n return state;\n}\n","/**\n * Coordinate conversion between EPSG:2169 (Luxembourg TM) and EPSG:4326 (WGS84).\n *\n * The Geoportail API operates internally in EPSG:2169 but also accepts\n * position arrays in EPSG:4326 via `lux.Map` constructor options.\n *\n * For precise server-side conversion the REST API itself is authoritative.\n * The formulas below use a 6-parameter Helmert + transverse Mercator approach\n * sufficient for Luxembourg's territory (~50 km radius).\n *\n * Reference: IGN-L / ACT official parameters for LUREF (EPSG:2169).\n */\n\n// LUREF / Luxembourg TM projection constants (EPSG:2169)\nconst FE = 80000; // False Easting (m)\nconst FN = 100000; // False Northing (m)\nconst LON0 = 6.16666666666667; // Central meridian (6°10') in degrees\nconst LAT0 = 49.8333333333333; // Latitude of origin (49°50') in degrees\nconst SCALE = 1.0; // Scale factor at central meridian\nconst A = 6378388.0; // Semi-major axis (Hayford / International 1924)\nconst F = 1 / 297.0; // Flattening\nconst B = A * (1 - F); // Semi-minor axis\n\nconst E2 = 1 - (B * B) / (A * A); // First eccentricity squared\n\n// Helmert 7-parameter shift: ETRS89 -> ED50 (approximate for Luxembourg)\n// These values transform WGS84 (≈ETRS89) to ED50 used by LUREF\nconst DX = -87.0;\nconst DY = -98.0;\nconst DZ = -121.0;\n\nfunction degToRad(d: number): number {\n return (d * Math.PI) / 180;\n}\n\nfunction radToDeg(r: number): number {\n return (r * 180) / Math.PI;\n}\n\n/**\n * Molodensky transformation: WGS84 -> ED50 (approximate, <1 m accuracy).\n */\nfunction wgs84ToEd50(\n lat: number,\n lon: number\n): { lat: number; lon: number } {\n const latR = degToRad(lat);\n const lonR = degToRad(lon);\n\n const sinLat = Math.sin(latR);\n const cosLat = Math.cos(latR);\n const sinLon = Math.sin(lonR);\n const cosLon = Math.cos(lonR);\n\n const aWgs = 6378137.0;\n const fWgs = 1 / 298.257223563;\n const bWgs = aWgs * (1 - fWgs);\n const e2Wgs = 1 - (bWgs * bWgs) / (aWgs * aWgs);\n\n const da = A - aWgs;\n const df = F - fWgs;\n\n const N = aWgs / Math.sqrt(1 - e2Wgs * sinLat * sinLat);\n const M =\n (aWgs * (1 - e2Wgs)) /\n Math.pow(1 - e2Wgs * sinLat * sinLat, 1.5);\n\n const dLat =\n (1 / M) *\n (N * (e2Wgs / (1 - e2Wgs)) * sinLat * cosLat * (da / aWgs) +\n (N / aWgs + 1) * sinLat * cosLat * df * (aWgs / bWgs) -\n (DX * sinLat * cosLon + DY * sinLat * sinLon - DZ * cosLat));\n\n const dLon =\n (1 / (N * cosLat)) * (-DX * sinLon + DY * cosLon);\n\n return {\n lat: lat + radToDeg(dLat),\n lon: lon + radToDeg(dLon),\n };\n}\n\n/**\n * ED50 -> WGS84 (inverse Molodensky, approximate).\n */\nfunction ed50ToWgs84(\n lat: number,\n lon: number\n): { lat: number; lon: number } {\n const latR = degToRad(lat);\n const lonR = degToRad(lon);\n\n const sinLat = Math.sin(latR);\n const cosLat = Math.cos(latR);\n const sinLon = Math.sin(lonR);\n const cosLon = Math.cos(lonR);\n\n const N = A / Math.sqrt(1 - E2 * sinLat * sinLat);\n const M = (A * (1 - E2)) / Math.pow(1 - E2 * sinLat * sinLat, 1.5);\n\n const da = 6378137.0 - A;\n const fWgs = 1 / 298.257223563;\n const df = fWgs - F;\n\n const dLat =\n (1 / M) *\n (N * (E2 / (1 - E2)) * sinLat * cosLat * (da / A) +\n (N / A + 1) * sinLat * cosLat * df * (A / B) +\n (DX * sinLat * cosLon + DY * sinLat * sinLon - DZ * cosLat));\n\n const dLon =\n (1 / (N * cosLat)) * (DX * sinLon - DY * cosLon);\n\n return {\n lat: lat + radToDeg(dLat),\n lon: lon + radToDeg(dLon),\n };\n}\n\n/**\n * Transverse Mercator forward projection (ED50 lat/lon -> LUREF easting/northing).\n */\nfunction tmForward(lat: number, lon: number): { easting: number; northing: number } {\n const latR = degToRad(lat);\n const lonR = degToRad(lon);\n const lon0R = degToRad(LON0);\n const lat0R = degToRad(LAT0);\n\n const sinLat = Math.sin(latR);\n const cosLat = Math.cos(latR);\n const tanLat = Math.tan(latR);\n\n const N = A / Math.sqrt(1 - E2 * sinLat * sinLat);\n const T = tanLat * tanLat;\n const C = (E2 / (1 - E2)) * cosLat * cosLat;\n const dl = lonR - lon0R;\n const XX = cosLat * dl;\n\n // Meridian arc from equator to lat\n const M = meridianArc(latR);\n const M0 = meridianArc(lat0R);\n\n const easting =\n FE +\n SCALE *\n N *\n (XX +\n (XX * XX * XX * (1 - T + C)) / 6 +\n (XX * XX * XX * XX * XX * (5 - 18 * T + T * T + 72 * C)) / 120);\n\n const northing =\n FN +\n SCALE *\n (M -\n M0 +\n N *\n tanLat *\n (XX * XX / 2 +\n (XX * XX * XX * XX * (5 - T + 9 * C + 4 * C * C)) / 24 +\n (XX * XX * XX * XX * XX * XX *\n (61 - 58 * T + T * T + 600 * C)) /\n 720));\n\n return { easting, northing };\n}\n\n/**\n * Transverse Mercator inverse projection (LUREF easting/northing -> ED50 lat/lon).\n */\nfunction tmInverse(easting: number, northing: number): { lat: number; lon: number } {\n const x = easting - FE;\n const y = northing - FN;\n const lat0R = degToRad(LAT0);\n const lon0R = degToRad(LON0);\n const M0 = meridianArc(lat0R);\n\n // Footpoint latitude\n const M1 = M0 + y / SCALE;\n const mu = M1 / (A * (1 - E2 / 4 - (3 * E2 * E2) / 64));\n\n const e1 = (1 - Math.sqrt(1 - E2)) / (1 + Math.sqrt(1 - E2));\n const phi1 =\n mu +\n ((3 * e1) / 2 - (27 * e1 * e1 * e1) / 32) * Math.sin(2 * mu) +\n ((21 * e1 * e1) / 16 - (55 * e1 * e1 * e1 * e1) / 32) *\n Math.sin(4 * mu) +\n ((151 * e1 * e1 * e1) / 96) * Math.sin(6 * mu);\n\n const sinPhi1 = Math.sin(phi1);\n const cosPhi1 = Math.cos(phi1);\n const tanPhi1 = Math.tan(phi1);\n\n const N1 = A / Math.sqrt(1 - E2 * sinPhi1 * sinPhi1);\n const T1 = tanPhi1 * tanPhi1;\n const C1 = (E2 / (1 - E2)) * cosPhi1 * cosPhi1;\n const R1 =\n (A * (1 - E2)) / Math.pow(1 - E2 * sinPhi1 * sinPhi1, 1.5);\n const D = x / (N1 * SCALE);\n\n const lat =\n phi1 -\n ((N1 * tanPhi1) / R1) *\n (D * D / 2 -\n (D * D * D * D * (5 + 3 * T1 + 10 * C1 - 4 * C1 * C1)) / 24 +\n (D * D * D * D * D * D *\n (61 + 90 * T1 + 298 * C1 + 45 * T1 * T1)) /\n 720);\n\n const lon =\n lon0R +\n (D -\n (D * D * D * (1 + 2 * T1 + C1)) / 6 +\n (D * D * D * D * D * (5 - 2 * C1 + 28 * T1 - 3 * C1 * C1)) / 120) /\n cosPhi1;\n\n return { lat: radToDeg(lat), lon: radToDeg(lon) };\n}\n\nfunction meridianArc(latR: number): number {\n const e2 = E2;\n const e4 = e2 * e2;\n const e6 = e4 * e2;\n return (\n A *\n ((1 - e2 / 4 - (3 * e4) / 64 - (5 * e6) / 256) * latR -\n ((3 * e2) / 8 + (3 * e4) / 32 + (45 * e6) / 1024) *\n Math.sin(2 * latR) +\n ((15 * e4) / 256 + (45 * e6) / 1024) * Math.sin(4 * latR) -\n ((35 * e6) / 3072) * Math.sin(6 * latR))\n );\n}\n\n/**\n * Convert WGS84 (lat/lon) to EPSG:2169 (easting/northing).\n */\nexport function latLonToLuref(\n lat: number,\n lon: number\n): { easting: number; northing: number } {\n const ed50 = wgs84ToEd50(lat, lon);\n return tmForward(ed50.lat, ed50.lon);\n}\n\n/**\n * Convert EPSG:2169 (easting/northing) to WGS84 (lat/lon).\n */\nexport function lurefToLatLon(\n easting: number,\n northing: number\n): { lat: number; lon: number } {\n const ed50 = tmInverse(easting, northing);\n return ed50ToWgs84(ed50.lat, ed50.lon);\n}\n","import React, {\n useEffect,\n useRef,\n forwardRef,\n useImperativeHandle,\n} from 'react';\nimport { useLuxApi } from '../hooks/useLuxApi';\nimport { lurefToLatLon, latLonToLuref } from '../utils/coordinates';\nimport type { LatLon, MapClickHandler, MarkerMode } from '../types';\nimport type { LuxMapInstance } from '../types/lux';\n\nexport interface GeoportailMapProps {\n /**\n * Initial center of the map.\n * Defaults to Luxembourg City (lat: 49.6116, lon: 6.1319).\n */\n center?: LatLon;\n\n /** Initial zoom level (1–20). Default: 12 */\n zoom?: number;\n\n /**\n * Background layer identifier.\n * Default: 'basemap_2015_global'\n */\n bgLayer?: string;\n\n /**\n * Controls pin/marker behaviour:\n * - 'none' — no marker\n * - 'fixed' — show a marker at `markerPosition` (does not move on click)\n * - 'click' — user clicks map to place/move the pin; fires `onMarkerPlace`\n *\n * Default: 'none'\n */\n markerMode?: MarkerMode;\n\n /**\n * Position of the marker when `markerMode` is 'fixed' or to pre-set an\n * initial pin when `markerMode` is 'click'.\n */\n markerPosition?: LatLon;\n\n /**\n * Called whenever the user places a pin (markerMode === 'click').\n * Receives the WGS84 lat/lon of the clicked point.\n */\n onMarkerPlace?: MapClickHandler;\n\n /** CSS class applied to the map container div */\n className?: string;\n\n /** Inline styles for the map container div */\n style?: React.CSSProperties;\n\n /** Additional numeric layer IDs to add on top of the background */\n layers?: number[];\n}\n\nexport interface GeoportailMapHandle {\n /** Returns the underlying lux.Map instance (or null before ready) */\n getLuxMap(): LuxMapInstance | null;\n /** Programmatically move the map center */\n setCenter(coords: LatLon): void;\n /** Programmatically set zoom */\n setZoom(zoom: number): void;\n}\n\nconst LUXEMBOURG_CITY: LatLon = { lat: 49.6116, lon: 6.1319 };\nconst DEFAULT_BG_LAYER = 'basemap_2015_global';\n\n/**\n * Renders a Geoportail Luxembourg map inside a React component.\n *\n * Expose a ref (`GeoportailMapHandle`) to access the underlying lux.Map instance\n * or imperatively control the view.\n */\nexport const GeoportailMap = forwardRef<GeoportailMapHandle, GeoportailMapProps>(\n function GeoportailMap(\n {\n center = LUXEMBOURG_CITY,\n zoom = 12,\n bgLayer = DEFAULT_BG_LAYER,\n markerMode = 'none',\n markerPosition,\n onMarkerPlace,\n className,\n style,\n layers,\n },\n ref\n ) {\n const luxApi = useLuxApi();\n const mapContainerRef = useRef<HTMLDivElement | null>(null);\n const mapRef = useRef<LuxMapInstance | null>(null);\n const markerLayerRef = useRef<unknown>(null);\n const clickListenerRef = useRef<((...args: unknown[]) => void) | null>(null);\n\n // Keep stable refs to callbacks so effects don't re-run on every render\n const onMarkerPlaceRef = useRef(onMarkerPlace);\n onMarkerPlaceRef.current = onMarkerPlace;\n\n // ------------------------------------------------------------------ map init\n useEffect(() => {\n if (luxApi.status !== 'ready') return;\n if (!mapContainerRef.current) return;\n\n const lux = luxApi.lux;\n const { easting, northing } = latLonToLuref(center.lat, center.lon);\n\n const mapInstance = new lux.Map({\n target: mapContainerRef.current,\n bgLayer,\n zoom,\n position: [easting, northing],\n ...(layers && layers.length > 0\n ? { layers, layerOpacities: layers.map(() => 1) }\n : {}),\n });\n\n mapRef.current = mapInstance;\n\n return () => {\n // lux.Map does not expose a destroy(); we clear our references\n mapRef.current = null;\n markerLayerRef.current = null;\n clickListenerRef.current = null;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [luxApi.status]);\n\n // ------------------------------------------------------------------ marker\n useEffect(() => {\n const map = mapRef.current;\n if (!map || luxApi.status !== 'ready') return;\n\n // Remove previous click listener\n if (clickListenerRef.current) {\n map.un('singleclick', clickListenerRef.current);\n clickListenerRef.current = null;\n }\n\n if (markerMode === 'none') {\n clearMarker(map, markerLayerRef);\n return;\n }\n\n const initialPos = markerPosition ?? (markerMode === 'fixed' ? center : undefined);\n if (initialPos) {\n placeMarker(map, initialPos, markerLayerRef);\n }\n\n if (markerMode === 'click') {\n const handler = (...args: unknown[]) => {\n // OpenLayers MapBrowserEvent — coordinate is in map projection (EPSG:2169)\n const evt = args[0] as { coordinate?: [number, number] };\n if (!evt.coordinate) return;\n\n const [e, n] = evt.coordinate;\n const latLon = lurefToLatLon(e, n);\n placeMarker(map, latLon, markerLayerRef);\n onMarkerPlaceRef.current?.(latLon);\n };\n\n clickListenerRef.current = handler;\n map.on('singleclick', handler);\n }\n }, [\n luxApi.status,\n markerMode,\n markerPosition?.lat,\n markerPosition?.lon,\n center.lat,\n center.lon,\n ]);\n\n // ------------------------------------------------------------------ imperative handle\n useImperativeHandle(ref, () => ({\n getLuxMap: () => mapRef.current,\n setCenter(coords: LatLon) {\n const map = mapRef.current;\n if (!map) return;\n const { easting, northing } = latLonToLuref(coords.lat, coords.lon);\n map.getView().setCenter([easting, northing]);\n },\n setZoom(z: number) {\n mapRef.current?.getView().setZoom(z);\n },\n }));\n\n // ------------------------------------------------------------------ render\n if (luxApi.status === 'error') {\n return (\n <div\n className={className}\n style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', background: '#f5f5f5', ...style }}\n >\n <span style={{ color: '#c00' }}>\n Failed to load Geoportail API: {luxApi.error.message}\n </span>\n </div>\n );\n }\n\n return (\n <div style={{ position: 'relative', ...style }} className={className}>\n {luxApi.status === 'loading' && (\n <div\n style={{\n position: 'absolute',\n inset: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n background: 'rgba(255,255,255,0.7)',\n zIndex: 10,\n }}\n >\n <span>Loading map…</span>\n </div>\n )}\n <div\n ref={mapContainerRef}\n style={{ width: '100%', height: '100%' }}\n />\n </div>\n );\n }\n);\n\n// ------------------------------------------------------------------ helpers\n\n/**\n * Place/move an SVG pin marker on the map.\n * lux.Map is built on OpenLayers 3 — we use ol.Overlay for the marker.\n */\nfunction placeMarker(\n map: LuxMapInstance,\n position: LatLon,\n layerRef: React.MutableRefObject<unknown>\n): void {\n // Prefer ol (OpenLayers global) if available\n const ol = (window as unknown as { ol?: OlLike }).ol;\n if (!ol) return;\n\n const { easting, northing } = latLonToLuref(position.lat, position.lon);\n\n // Reuse existing overlay or create a new one\n if (layerRef.current) {\n const overlay = layerRef.current as OlOverlay;\n overlay.setPosition([easting, northing]);\n return;\n }\n\n const el = document.createElement('div');\n el.innerHTML = PIN_SVG;\n el.style.cssText =\n 'cursor:pointer;transform:translate(-50%,-100%);line-height:0;';\n\n const overlay = new ol.Overlay({\n element: el,\n positioning: 'bottom-center',\n stopEvent: false,\n });\n\n overlay.setPosition([easting, northing]);\n (map as unknown as { addOverlay(o: OlOverlay): void }).addOverlay(overlay);\n layerRef.current = overlay;\n}\n\nfunction clearMarker(\n _map: LuxMapInstance,\n layerRef: React.MutableRefObject<unknown>\n): void {\n if (!layerRef.current) return;\n const ol = (window as unknown as { ol?: OlLike }).ol;\n if (!ol) return;\n // Overlay doesn't have a built-in remove on the overlay itself;\n // set position to undefined to hide it\n (layerRef.current as OlOverlay).setPosition(undefined);\n layerRef.current = null;\n}\n\n// Minimal pin SVG (red teardrop, 30×40)\nconst PIN_SVG = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"30\" height=\"40\" viewBox=\"0 0 30 40\">\n <path d=\"M15 0C7.268 0 1 6.268 1 14c0 10.5 14 26 14 26S29 24.5 29 14C29 6.268 22.732 0 15 0z\"\n fill=\"#e53935\" stroke=\"#b71c1c\" stroke-width=\"1.5\"/>\n <circle cx=\"15\" cy=\"14\" r=\"5\" fill=\"white\"/>\n</svg>`;\n\n// Minimal OL type stubs used only within this file\ninterface OlOverlay {\n setPosition(pos: [number, number] | undefined): void;\n}\n\ninterface OlLike {\n Overlay: new (opts: { element: HTMLElement; positioning: string; stopEvent: boolean }) => OlOverlay;\n}\n","import { useState, useEffect, useCallback, useRef } from 'react';\nimport { latLonToLuref } from '../utils/coordinates';\nimport type { LatLon, Address } from '../types';\n\nconst REVERSE_GEOCODE_URL = 'https://api.geoportail.lu/geocoder/reverseGeocode';\n\nexport type ReverseGeocodeState =\n | { status: 'idle'; address: null; error: null }\n | { status: 'loading'; address: null; error: null }\n | { status: 'success'; address: Address; error: null }\n | { status: 'error'; address: null; error: Error };\n\n/**\n * Hook for reverse geocoding: convert a WGS84 lat/lon to a Luxembourg address.\n *\n * Uses the Geoportail REST reverse geocode endpoint — no API key required.\n *\n * @example\n * const { state, lookup } = useReverseGeocode();\n * // ...\n * lookup({ lat: 49.6116, lon: 6.1319 });\n * if (state.status === 'success') console.log(state.address.label);\n */\nexport function useReverseGeocode() {\n const [state, setState] = useState<ReverseGeocodeState>({\n status: 'idle',\n address: null,\n error: null,\n });\n\n const abortRef = useRef<AbortController | null>(null);\n\n useEffect(() => () => { abortRef.current?.abort(); }, []);\n\n const lookup = useCallback(async (position: LatLon) => {\n // Cancel any in-flight request\n abortRef.current?.abort();\n const controller = new AbortController();\n abortRef.current = controller;\n\n setState({ status: 'loading', address: null, error: null });\n\n try {\n const { easting, northing } = latLonToLuref(position.lat, position.lon);\n\n const url = new URL(REVERSE_GEOCODE_URL);\n url.searchParams.set('easting', String(easting));\n url.searchParams.set('northing', String(northing));\n\n const res = await fetch(url.toString(), { signal: controller.signal });\n\n if (!res.ok) {\n throw new Error(`Reverse geocode request failed: ${res.status} ${res.statusText}`);\n }\n\n const data = (await res.json()) as {\n results?: Array<{\n easting: number;\n northing: number;\n name?: string;\n distance?: number;\n }>;\n };\n\n const first = data.results?.[0];\n if (!first) {\n throw new Error('No results returned for this position');\n }\n\n setState({\n status: 'success',\n address: {\n label: first.name ?? '',\n distance: first.distance ?? 0,\n easting: first.easting,\n northing: first.northing,\n },\n error: null,\n });\n } catch (err: unknown) {\n if (err instanceof DOMException && err.name === 'AbortError') return;\n setState({\n status: 'error',\n address: null,\n error: err instanceof Error ? err : new Error(String(err)),\n });\n }\n }, []);\n\n const reset = useCallback(() => {\n abortRef.current?.abort();\n setState({ status: 'idle', address: null, error: null });\n }, []);\n\n return { state, lookup, reset };\n}\n","import { useState, useEffect, useCallback, useRef } from 'react';\nimport { lurefToLatLon } from '../utils/coordinates';\nimport type { GeocodeQuery, LatLon } from '../types';\n\nconst GEOCODE_URL = 'https://apiv3.geoportail.lu/geocode/search';\n\nexport interface GeocodeResultItem {\n latLon: LatLon;\n easting: number;\n northing: number;\n accuracy: number;\n street?: string;\n num?: string;\n zip?: string;\n locality?: string;\n}\n\nexport type GeocodeState =\n | { status: 'idle'; results: null; error: null }\n | { status: 'loading'; results: null; error: null }\n | { status: 'success'; results: GeocodeResultItem[]; error: null }\n | { status: 'error'; results: null; error: Error };\n\n/**\n * Hook for forward geocoding: search for a Luxembourg address and get coordinates.\n *\n * @example\n * const { state, search } = useGeocode();\n * search({ queryString: '1 rue du Fort Thüngen, Luxembourg' });\n * if (state.status === 'success') {\n * const { lat, lon } = state.results[0].latLon;\n * }\n */\nexport function useGeocode() {\n const [state, setState] = useState<GeocodeState>({\n status: 'idle',\n results: null,\n error: null,\n });\n\n const abortRef = useRef<AbortController | null>(null);\n\n useEffect(() => () => { abortRef.current?.abort(); }, []);\n\n const search = useCallback(async (query: GeocodeQuery) => {\n abortRef.current?.abort();\n const controller = new AbortController();\n abortRef.current = controller;\n\n setState({ status: 'loading', results: null, error: null });\n\n try {\n const url = new URL(GEOCODE_URL);\n\n if (query.queryString) {\n url.searchParams.set('queryString', query.queryString);\n } else {\n if (query.num) url.searchParams.set('num', query.num);\n if (query.street) url.searchParams.set('street', query.street);\n if (query.zip) url.searchParams.set('zip', query.zip);\n if (query.locality) url.searchParams.set('locality', query.locality);\n }\n\n const res = await fetch(url.toString(), { signal: controller.signal });\n\n if (!res.ok) {\n throw new Error(`Geocode request failed: ${res.status} ${res.statusText}`);\n }\n\n const data = (await res.json()) as {\n results?: Array<{\n easting: number;\n northing: number;\n accuracy?: number;\n AddressDetails?: {\n street?: string;\n number?: string;\n zip?: string;\n locality?: string;\n };\n }>;\n };\n\n const results: GeocodeResultItem[] = (data.results ?? []).map((r) => ({\n latLon: lurefToLatLon(r.easting, r.northing),\n easting: r.easting,\n northing: r.northing,\n accuracy: r.accuracy ?? 0,\n street: r.AddressDetails?.street,\n num: r.AddressDetails?.number,\n zip: r.AddressDetails?.zip,\n locality: r.AddressDetails?.locality,\n }));\n\n setState({ status: 'success', results, error: null });\n } catch (err: unknown) {\n if (err instanceof DOMException && err.name === 'AbortError') return;\n setState({\n status: 'error',\n results: null,\n error: err instanceof Error ? err : new Error(String(err)),\n });\n }\n }, []);\n\n const reset = useCallback(() => {\n abortRef.current?.abort();\n setState({ status: 'idle', results: null, error: null });\n }, []);\n\n return { state, search, reset };\n}\n"],"names":["LUX_BASE_URL","LUX_PROTOCOL","LUX_I18N_URL","LUX_STYLESHEET_URL","LUX_VENDOR_URL","LUX_API_URL","LUX_STYLESHEET_ID","LUX_VENDOR_SCRIPT_ID","LUX_API_SCRIPT_ID","ELEMENT_STATUS_ATTRIBUTE","loadPromise","loadLuxApi","loadLuxApiInternal","error","pollForLux","resolve","reject","attempts","check","configureLux","loadStylesheetOnce","loadScriptOnce","waitForLux","lux","id","src","existing","waitForElementLoad","script","attachLoadHandlers","href","link","element","resourceUrl","kind","status","onLoad","onError","handleLoad","cleanup","handleError","useLuxApi","state","setState","useState","useEffect","cancelled","err","FE","FN","LON0","LAT0","SCALE","A","F","B","E2","DX","DY","DZ","degToRad","d","radToDeg","r","wgs84ToEd50","lat","lon","latR","lonR","sinLat","cosLat","sinLon","cosLon","aWgs","fWgs","bWgs","e2Wgs","da","df","N","dLat","dLon","ed50ToWgs84","M","tmForward","lon0R","lat0R","tanLat","T","C","dl","XX","meridianArc","M0","easting","northing","tmInverse","x","y","mu","e1","phi1","sinPhi1","cosPhi1","tanPhi1","N1","T1","C1","R1","D","e2","e4","e6","latLonToLuref","ed50","lurefToLatLon","LUXEMBOURG_CITY","DEFAULT_BG_LAYER","GeoportailMap","forwardRef","center","zoom","bgLayer","markerMode","markerPosition","onMarkerPlace","className","style","layers","ref","luxApi","mapContainerRef","useRef","mapRef","markerLayerRef","clickListenerRef","onMarkerPlaceRef","mapInstance","map","clearMarker","initialPos","placeMarker","handler","args","evt","e","n","latLon","_a","useImperativeHandle","coords","z","jsx","jsxs","position","layerRef","ol","el","PIN_SVG","overlay","_map","REVERSE_GEOCODE_URL","useReverseGeocode","abortRef","lookup","useCallback","controller","url","res","first","_b","reset","GEOCODE_URL","useGeocode","search","query","results","_c","_d"],"mappings":"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"}
1
+ {"version":3,"file":"react-geoportail.umd.cjs","sources":["../src/utils/loader.ts","../src/hooks/useLuxApi.ts","../src/utils/coordinates.ts","../src/components/GeoportailMap.tsx","../src/hooks/useReverseGeocode.ts","../src/hooks/useGeocode.ts"],"sourcesContent":["/**\n * Dynamically injects the Geoportail v3 assets and resolves when\n * the global `lux` namespace is available.\n */\n\nconst LUX_BASE_URL = 'https://apiv3.geoportail.lu/';\nconst LUX_PROTOCOL = 'https';\nconst LUX_I18N_URL = 'https://apiv3.geoportail.lu/static-ngeo/build/fr.json';\nconst LUX_STYLESHEET_URL = 'https://apiv3.geoportail.lu/static-ngeo/build/apiv3.css';\nconst LUX_VENDOR_URL = 'https://apiv3.geoportail.lu/static-ngeo/build/vendor.js';\nconst LUX_API_URL = 'https://apiv3.geoportail.lu/static-ngeo/build/apiv3.js';\n\nconst LUX_STYLESHEET_ID = 'geoportail-apiv3-css';\nconst LUX_VENDOR_SCRIPT_ID = 'geoportail-apiv3-vendor';\nconst LUX_API_SCRIPT_ID = 'geoportail-apiv3-script';\n\nconst ELEMENT_STATUS_ATTRIBUTE = 'data-geoportail-status';\n\nlet loadPromise: Promise<void> | null = null;\n\n/**\n * Loads the Geoportail API assets exactly once.\n * Safe to call multiple times — subsequent calls return the same promise.\n */\nexport function loadLuxApi(): Promise<void> {\n if (loadPromise) return loadPromise;\n\n if (typeof window === 'undefined' || typeof document === 'undefined') {\n return Promise.reject(new Error('loadLuxApi must be called in a browser environment'));\n }\n\n loadPromise = loadLuxApiInternal().catch((error: unknown) => {\n loadPromise = null;\n throw error instanceof Error ? error : new Error(String(error));\n });\n\n return loadPromise;\n}\n\n/**\n * The lux API may initialise asynchronously after the scripts load.\n * Poll until window.lux is defined (max ~5 s).\n */\nfunction pollForLux(resolve: () => void, reject: (err: Error) => void): void {\n const maxAttempts = 100;\n let attempts = 0;\n\n const check = () => {\n if (window.lux) {\n resolve();\n return;\n }\n if (attempts++ >= maxAttempts) {\n loadPromise = null;\n reject(new Error('Timed out waiting for window.lux to be defined'));\n return;\n }\n setTimeout(check, 50);\n };\n\n check();\n}\n\nasync function loadLuxApiInternal(): Promise<void> {\n if (window.lux) {\n configureLux(window.lux);\n return;\n }\n\n await loadStylesheetOnce(LUX_STYLESHEET_ID, LUX_STYLESHEET_URL);\n await loadScriptOnce(LUX_VENDOR_SCRIPT_ID, LUX_VENDOR_URL);\n await loadScriptOnce(LUX_API_SCRIPT_ID, LUX_API_URL);\n await waitForLux();\n configureLux(window.lux!);\n}\n\nfunction waitForLux(): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n pollForLux(resolve, reject);\n });\n}\n\nfunction configureLux(lux: NonNullable<Window['lux']>): void {\n lux.setBaseUrl(LUX_BASE_URL, LUX_PROTOCOL);\n lux.setI18nUrl(LUX_I18N_URL);\n}\n\nfunction loadScriptOnce(id: string, src: string): Promise<void> {\n const existing = document.getElementById(id) as HTMLScriptElement | null;\n if (existing) {\n return waitForElementLoad(existing, src, 'script');\n }\n\n return new Promise<void>((resolve, reject) => {\n const script = document.createElement('script');\n script.id = id;\n script.src = src;\n script.async = false;\n script.setAttribute(ELEMENT_STATUS_ATTRIBUTE, 'loading');\n\n const cleanup = attachLoadHandlers(\n script,\n () => resolve(),\n () => reject(new Error(`Failed to load Geoportail script from ${src}`)),\n 'script'\n );\n\n document.head.appendChild(script);\n void cleanup;\n });\n}\n\nfunction loadStylesheetOnce(id: string, href: string): Promise<void> {\n const existing = document.getElementById(id) as HTMLLinkElement | null;\n if (existing) {\n return waitForElementLoad(existing, href, 'stylesheet');\n }\n\n return new Promise<void>((resolve, reject) => {\n const link = document.createElement('link');\n link.id = id;\n link.rel = 'stylesheet';\n link.href = href;\n link.setAttribute(ELEMENT_STATUS_ATTRIBUTE, 'loading');\n\n const cleanup = attachLoadHandlers(\n link,\n () => resolve(),\n () => reject(new Error(`Failed to load Geoportail stylesheet from ${href}`)),\n 'stylesheet'\n );\n\n document.head.appendChild(link);\n void cleanup;\n });\n}\n\nfunction waitForElementLoad(\n element: HTMLScriptElement | HTMLLinkElement,\n resourceUrl: string,\n kind: 'script' | 'stylesheet'\n): Promise<void> {\n const status = element.getAttribute(ELEMENT_STATUS_ATTRIBUTE);\n\n if (status === 'loaded') {\n return Promise.resolve();\n }\n\n if (status === 'error') {\n element.remove();\n return Promise.reject(new Error(`Failed to load Geoportail ${kind} from ${resourceUrl}`));\n }\n\n return new Promise<void>((resolve, reject) => {\n const cleanup = attachLoadHandlers(\n element,\n () => resolve(),\n () => reject(new Error(`Failed to load Geoportail ${kind} from ${resourceUrl}`)),\n kind\n );\n\n void cleanup;\n });\n}\n\nfunction attachLoadHandlers(\n element: HTMLScriptElement | HTMLLinkElement,\n onLoad: () => void,\n onError: () => void,\n kind: 'script' | 'stylesheet'\n): () => void {\n const handleLoad = () => {\n element.setAttribute(ELEMENT_STATUS_ATTRIBUTE, 'loaded');\n cleanup();\n onLoad();\n };\n\n const handleError = () => {\n element.setAttribute(ELEMENT_STATUS_ATTRIBUTE, 'error');\n cleanup();\n element.remove();\n onError();\n };\n\n const cleanup = () => {\n element.removeEventListener('load', handleLoad);\n element.removeEventListener('error', handleError);\n };\n\n element.addEventListener('load', handleLoad, { once: true });\n element.addEventListener('error', handleError, { once: true });\n\n if (kind === 'stylesheet') {\n const link = element as HTMLLinkElement;\n if (link.sheet) {\n handleLoad();\n }\n } else {\n const script = element as HTMLScriptElement;\n if (script.dataset.geoportailStatus === 'loaded') {\n handleLoad();\n }\n }\n\n return cleanup;\n}\n","import { useState, useEffect } from 'react';\nimport { loadLuxApi } from '../utils/loader';\nimport type { LuxNamespace } from '../types/lux';\n\nexport type LuxApiState =\n | { status: 'loading'; lux: null; error: null }\n | { status: 'ready'; lux: LuxNamespace; error: null }\n | { status: 'error'; lux: null; error: Error };\n\n/**\n * Loads the Geoportail runtime assets and returns the `lux` namespace once ready.\n * Deduplicates the asset load — safe to call from multiple components.\n */\nexport function useLuxApi(): LuxApiState {\n const [state, setState] = useState<LuxApiState>({\n status: 'loading',\n lux: null,\n error: null,\n });\n\n useEffect(() => {\n let cancelled = false;\n\n loadLuxApi()\n .then(() => {\n if (!cancelled) {\n setState({ status: 'ready', lux: window.lux!, error: null });\n }\n })\n .catch((err: unknown) => {\n if (!cancelled) {\n setState({\n status: 'error',\n lux: null,\n error: err instanceof Error ? err : new Error(String(err)),\n });\n }\n });\n\n return () => {\n cancelled = true;\n };\n }, []);\n\n return state;\n}\n","/**\n * Coordinate conversion between EPSG:2169 (Luxembourg TM) and EPSG:4326 (WGS84).\n *\n * The Geoportail API operates internally in EPSG:2169 but also accepts\n * position arrays in EPSG:4326 via `lux.Map` constructor options.\n *\n * For precise server-side conversion the REST API itself is authoritative.\n * The formulas below use a 6-parameter Helmert + transverse Mercator approach\n * sufficient for Luxembourg's territory (~50 km radius).\n *\n * Reference: IGN-L / ACT official parameters for LUREF (EPSG:2169).\n */\n\n// LUREF / Luxembourg TM projection constants (EPSG:2169)\nconst FE = 80000; // False Easting (m)\nconst FN = 100000; // False Northing (m)\nconst LON0 = 6.16666666666667; // Central meridian (6°10') in degrees\nconst LAT0 = 49.8333333333333; // Latitude of origin (49°50') in degrees\nconst SCALE = 1.0; // Scale factor at central meridian\nconst A = 6378388.0; // Semi-major axis (Hayford / International 1924)\nconst F = 1 / 297.0; // Flattening\nconst B = A * (1 - F); // Semi-minor axis\n\nconst E2 = 1 - (B * B) / (A * A); // First eccentricity squared\n\n// Helmert 7-parameter shift: ETRS89 -> ED50 (approximate for Luxembourg)\n// These values transform WGS84 (≈ETRS89) to ED50 used by LUREF\nconst DX = -87.0;\nconst DY = -98.0;\nconst DZ = -121.0;\n\nfunction degToRad(d: number): number {\n return (d * Math.PI) / 180;\n}\n\nfunction radToDeg(r: number): number {\n return (r * 180) / Math.PI;\n}\n\n/**\n * Molodensky transformation: WGS84 -> ED50 (approximate, <1 m accuracy).\n */\nfunction wgs84ToEd50(\n lat: number,\n lon: number\n): { lat: number; lon: number } {\n const latR = degToRad(lat);\n const lonR = degToRad(lon);\n\n const sinLat = Math.sin(latR);\n const cosLat = Math.cos(latR);\n const sinLon = Math.sin(lonR);\n const cosLon = Math.cos(lonR);\n\n const aWgs = 6378137.0;\n const fWgs = 1 / 298.257223563;\n const bWgs = aWgs * (1 - fWgs);\n const e2Wgs = 1 - (bWgs * bWgs) / (aWgs * aWgs);\n\n const da = A - aWgs;\n const df = F - fWgs;\n\n const N = aWgs / Math.sqrt(1 - e2Wgs * sinLat * sinLat);\n const M =\n (aWgs * (1 - e2Wgs)) /\n Math.pow(1 - e2Wgs * sinLat * sinLat, 1.5);\n\n const dLat =\n (1 / M) *\n (N * (e2Wgs / (1 - e2Wgs)) * sinLat * cosLat * (da / aWgs) +\n (N / aWgs + 1) * sinLat * cosLat * df * (aWgs / bWgs) -\n (DX * sinLat * cosLon + DY * sinLat * sinLon - DZ * cosLat));\n\n const dLon =\n (1 / (N * cosLat)) * (-DX * sinLon + DY * cosLon);\n\n return {\n lat: lat + radToDeg(dLat),\n lon: lon + radToDeg(dLon),\n };\n}\n\n/**\n * ED50 -> WGS84 (inverse Molodensky, approximate).\n */\nfunction ed50ToWgs84(\n lat: number,\n lon: number\n): { lat: number; lon: number } {\n const latR = degToRad(lat);\n const lonR = degToRad(lon);\n\n const sinLat = Math.sin(latR);\n const cosLat = Math.cos(latR);\n const sinLon = Math.sin(lonR);\n const cosLon = Math.cos(lonR);\n\n const N = A / Math.sqrt(1 - E2 * sinLat * sinLat);\n const M = (A * (1 - E2)) / Math.pow(1 - E2 * sinLat * sinLat, 1.5);\n\n const da = 6378137.0 - A;\n const fWgs = 1 / 298.257223563;\n const df = fWgs - F;\n\n const dLat =\n (1 / M) *\n (N * (E2 / (1 - E2)) * sinLat * cosLat * (da / A) +\n (N / A + 1) * sinLat * cosLat * df * (A / B) +\n (DX * sinLat * cosLon + DY * sinLat * sinLon - DZ * cosLat));\n\n const dLon =\n (1 / (N * cosLat)) * (DX * sinLon - DY * cosLon);\n\n return {\n lat: lat + radToDeg(dLat),\n lon: lon + radToDeg(dLon),\n };\n}\n\n/**\n * Transverse Mercator forward projection (ED50 lat/lon -> LUREF easting/northing).\n */\nfunction tmForward(lat: number, lon: number): { easting: number; northing: number } {\n const latR = degToRad(lat);\n const lonR = degToRad(lon);\n const lon0R = degToRad(LON0);\n const lat0R = degToRad(LAT0);\n\n const sinLat = Math.sin(latR);\n const cosLat = Math.cos(latR);\n const tanLat = Math.tan(latR);\n\n const N = A / Math.sqrt(1 - E2 * sinLat * sinLat);\n const T = tanLat * tanLat;\n const C = (E2 / (1 - E2)) * cosLat * cosLat;\n const dl = lonR - lon0R;\n const XX = cosLat * dl;\n\n // Meridian arc from equator to lat\n const M = meridianArc(latR);\n const M0 = meridianArc(lat0R);\n\n const easting =\n FE +\n SCALE *\n N *\n (XX +\n (XX * XX * XX * (1 - T + C)) / 6 +\n (XX * XX * XX * XX * XX * (5 - 18 * T + T * T + 72 * C)) / 120);\n\n const northing =\n FN +\n SCALE *\n (M -\n M0 +\n N *\n tanLat *\n (XX * XX / 2 +\n (XX * XX * XX * XX * (5 - T + 9 * C + 4 * C * C)) / 24 +\n (XX * XX * XX * XX * XX * XX *\n (61 - 58 * T + T * T + 600 * C)) /\n 720));\n\n return { easting, northing };\n}\n\n/**\n * Transverse Mercator inverse projection (LUREF easting/northing -> ED50 lat/lon).\n */\nfunction tmInverse(easting: number, northing: number): { lat: number; lon: number } {\n const x = easting - FE;\n const y = northing - FN;\n const lat0R = degToRad(LAT0);\n const lon0R = degToRad(LON0);\n const M0 = meridianArc(lat0R);\n\n // Footpoint latitude\n const M1 = M0 + y / SCALE;\n const mu = M1 / (A * (1 - E2 / 4 - (3 * E2 * E2) / 64));\n\n const e1 = (1 - Math.sqrt(1 - E2)) / (1 + Math.sqrt(1 - E2));\n const phi1 =\n mu +\n ((3 * e1) / 2 - (27 * e1 * e1 * e1) / 32) * Math.sin(2 * mu) +\n ((21 * e1 * e1) / 16 - (55 * e1 * e1 * e1 * e1) / 32) *\n Math.sin(4 * mu) +\n ((151 * e1 * e1 * e1) / 96) * Math.sin(6 * mu);\n\n const sinPhi1 = Math.sin(phi1);\n const cosPhi1 = Math.cos(phi1);\n const tanPhi1 = Math.tan(phi1);\n\n const N1 = A / Math.sqrt(1 - E2 * sinPhi1 * sinPhi1);\n const T1 = tanPhi1 * tanPhi1;\n const C1 = (E2 / (1 - E2)) * cosPhi1 * cosPhi1;\n const R1 =\n (A * (1 - E2)) / Math.pow(1 - E2 * sinPhi1 * sinPhi1, 1.5);\n const D = x / (N1 * SCALE);\n\n const lat =\n phi1 -\n ((N1 * tanPhi1) / R1) *\n (D * D / 2 -\n (D * D * D * D * (5 + 3 * T1 + 10 * C1 - 4 * C1 * C1)) / 24 +\n (D * D * D * D * D * D *\n (61 + 90 * T1 + 298 * C1 + 45 * T1 * T1)) /\n 720);\n\n const lon =\n lon0R +\n (D -\n (D * D * D * (1 + 2 * T1 + C1)) / 6 +\n (D * D * D * D * D * (5 - 2 * C1 + 28 * T1 - 3 * C1 * C1)) / 120) /\n cosPhi1;\n\n return { lat: radToDeg(lat), lon: radToDeg(lon) };\n}\n\nfunction meridianArc(latR: number): number {\n const e2 = E2;\n const e4 = e2 * e2;\n const e6 = e4 * e2;\n return (\n A *\n ((1 - e2 / 4 - (3 * e4) / 64 - (5 * e6) / 256) * latR -\n ((3 * e2) / 8 + (3 * e4) / 32 + (45 * e6) / 1024) *\n Math.sin(2 * latR) +\n ((15 * e4) / 256 + (45 * e6) / 1024) * Math.sin(4 * latR) -\n ((35 * e6) / 3072) * Math.sin(6 * latR))\n );\n}\n\n/**\n * Convert WGS84 (lat/lon) to EPSG:2169 (easting/northing).\n */\nexport function latLonToLuref(\n lat: number,\n lon: number\n): { easting: number; northing: number } {\n const ed50 = wgs84ToEd50(lat, lon);\n return tmForward(ed50.lat, ed50.lon);\n}\n\n/**\n * Convert EPSG:2169 (easting/northing) to WGS84 (lat/lon).\n */\nexport function lurefToLatLon(\n easting: number,\n northing: number\n): { lat: number; lon: number } {\n const ed50 = tmInverse(easting, northing);\n return ed50ToWgs84(ed50.lat, ed50.lon);\n}\n","import React, {\n useEffect,\n useRef,\n forwardRef,\n useImperativeHandle,\n} from 'react';\nimport { useLuxApi } from '../hooks/useLuxApi';\nimport { lurefToLatLon, latLonToLuref } from '../utils/coordinates';\nimport type { LatLon, MapClickHandler, MarkerMode } from '../types';\nimport type { LuxMapInstance } from '../types/lux';\n\nconst DEFAULT_CLICK_SOURCE_PROJECTION = 'EPSG:3857';\nconst WGS84_PROJECTION = 'EPSG:4326';\n\nexport interface GeoportailMapProps {\n /**\n * Initial center of the map.\n * Defaults to Luxembourg City (lat: 49.6116, lon: 6.1319).\n */\n center?: LatLon;\n\n /** Initial zoom level (1–20). Default: 12 */\n zoom?: number;\n\n /**\n * Background layer identifier.\n * Default: 'basemap_2015_global'\n */\n bgLayer?: string;\n\n /**\n * Controls pin/marker behaviour:\n * - 'none' — no marker\n * - 'fixed' — show a marker at `markerPosition` (does not move on click)\n * - 'click' — user clicks map to place/move the pin; fires `onMarkerPlace`\n *\n * Default: 'none'\n */\n markerMode?: MarkerMode;\n\n /**\n * Position of the marker when `markerMode` is 'fixed' or to pre-set an\n * initial pin when `markerMode` is 'click'.\n */\n markerPosition?: LatLon;\n\n /**\n * Called whenever the user places a pin (markerMode === 'click').\n * Receives the WGS84 lat/lon of the clicked point.\n */\n onMarkerPlace?: MapClickHandler;\n\n /** CSS class applied to the map container div */\n className?: string;\n\n /** Inline styles for the map container div */\n style?: React.CSSProperties;\n\n /** Additional numeric layer IDs to add on top of the background */\n layers?: number[];\n}\n\nexport interface GeoportailMapHandle {\n /** Returns the underlying lux.Map instance (or null before ready) */\n getLuxMap(): LuxMapInstance | null;\n /** Programmatically move the map center */\n setCenter(coords: LatLon): void;\n /** Programmatically set zoom */\n setZoom(zoom: number): void;\n}\n\nconst LUXEMBOURG_CITY: LatLon = { lat: 49.6116, lon: 6.1319 };\nconst DEFAULT_BG_LAYER = 'basemap_2015_global';\n\n/**\n * Renders a Geoportail Luxembourg map inside a React component.\n *\n * Expose a ref (`GeoportailMapHandle`) to access the underlying lux.Map instance\n * or imperatively control the view.\n */\nexport const GeoportailMap = forwardRef<GeoportailMapHandle, GeoportailMapProps>(\n function GeoportailMap(\n {\n center = LUXEMBOURG_CITY,\n zoom = 12,\n bgLayer = DEFAULT_BG_LAYER,\n markerMode = 'none',\n markerPosition,\n onMarkerPlace,\n className,\n style,\n layers,\n },\n ref\n ) {\n const luxApi = useLuxApi();\n const mapContainerRef = useRef<HTMLDivElement | null>(null);\n const mapRef = useRef<LuxMapInstance | null>(null);\n const markerLayerRef = useRef<unknown>(null);\n const clickListenerRef = useRef<((...args: unknown[]) => void) | null>(null);\n\n // Keep stable refs to callbacks so effects don't re-run on every render\n const onMarkerPlaceRef = useRef(onMarkerPlace);\n onMarkerPlaceRef.current = onMarkerPlace;\n\n // ------------------------------------------------------------------ map init\n useEffect(() => {\n if (luxApi.status !== 'ready') return;\n if (!mapContainerRef.current) return;\n\n const lux = luxApi.lux;\n const { easting, northing } = latLonToLuref(center.lat, center.lon);\n\n const mapInstance = new lux.Map({\n target: mapContainerRef.current,\n bgLayer,\n zoom,\n position: [easting, northing],\n ...(layers && layers.length > 0\n ? { layers, layerOpacities: layers.map(() => 1) }\n : {}),\n });\n\n mapRef.current = mapInstance;\n\n return () => {\n // lux.Map does not expose a destroy(); we clear our references\n mapRef.current = null;\n markerLayerRef.current = null;\n clickListenerRef.current = null;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [luxApi.status]);\n\n // ------------------------------------------------------------------ marker\n useEffect(() => {\n const map = mapRef.current;\n if (!map || luxApi.status !== 'ready') return;\n\n // Remove previous click listener\n if (clickListenerRef.current) {\n map.un('singleclick', clickListenerRef.current);\n clickListenerRef.current = null;\n }\n\n if (markerMode === 'none') {\n clearMarker(map, markerLayerRef);\n return;\n }\n\n const initialPos = markerPosition ?? (markerMode === 'fixed' ? center : undefined);\n if (initialPos) {\n placeMarker(map, initialPos, markerLayerRef);\n }\n\n if (markerMode === 'click') {\n const handler = (...args: unknown[]) => {\n // Raw OpenLayers click coordinates are in the map view projection, not WGS84/LUREF.\n const evt = args[0] as { coordinate?: [number, number] };\n if (!evt.coordinate) return;\n\n const latLon = convertMapClickCoordinateToLatLon(map, evt.coordinate);\n placeMarker(map, latLon, markerLayerRef);\n onMarkerPlaceRef.current?.(latLon);\n };\n\n clickListenerRef.current = handler;\n map.on('singleclick', handler);\n }\n }, [\n luxApi.status,\n markerMode,\n markerPosition?.lat,\n markerPosition?.lon,\n center.lat,\n center.lon,\n ]);\n\n // ------------------------------------------------------------------ imperative handle\n useImperativeHandle(ref, () => ({\n getLuxMap: () => mapRef.current,\n setCenter(coords: LatLon) {\n const map = mapRef.current;\n if (!map) return;\n const { easting, northing } = latLonToLuref(coords.lat, coords.lon);\n map.getView().setCenter([easting, northing]);\n },\n setZoom(z: number) {\n mapRef.current?.getView().setZoom(z);\n },\n }));\n\n // ------------------------------------------------------------------ render\n if (luxApi.status === 'error') {\n return (\n <div\n className={className}\n style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', background: '#f5f5f5', ...style }}\n >\n <span style={{ color: '#c00' }}>\n Failed to load Geoportail API: {luxApi.error.message}\n </span>\n </div>\n );\n }\n\n return (\n <div style={{ position: 'relative', ...style }} className={className}>\n {luxApi.status === 'loading' && (\n <div\n style={{\n position: 'absolute',\n inset: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n background: 'rgba(255,255,255,0.7)',\n zIndex: 10,\n }}\n >\n <span>Loading map…</span>\n </div>\n )}\n <div\n ref={mapContainerRef}\n style={{ width: '100%', height: '100%' }}\n />\n </div>\n );\n }\n);\n\n// ------------------------------------------------------------------ helpers\n\n/**\n * Place/move an SVG pin marker on the map.\n * lux.Map is built on OpenLayers 3 — we use ol.Overlay for the marker.\n */\nfunction placeMarker(\n map: LuxMapInstance,\n position: LatLon,\n layerRef: React.MutableRefObject<unknown>\n): void {\n // Prefer ol (OpenLayers global) if available\n const ol = (window as unknown as { ol?: OlLike }).ol;\n if (!ol) return;\n\n const { easting, northing } = latLonToLuref(position.lat, position.lon);\n\n // Reuse existing overlay or create a new one\n if (layerRef.current) {\n const overlay = layerRef.current as OlOverlay;\n overlay.setPosition([easting, northing]);\n return;\n }\n\n const el = document.createElement('div');\n el.innerHTML = PIN_SVG;\n el.style.cssText =\n 'cursor:pointer;transform:translate(-50%,-100%);line-height:0;';\n\n const overlay = new ol.Overlay({\n element: el,\n positioning: 'bottom-center',\n stopEvent: false,\n });\n\n overlay.setPosition([easting, northing]);\n (map as unknown as { addOverlay(o: OlOverlay): void }).addOverlay(overlay);\n layerRef.current = overlay;\n}\n\nfunction clearMarker(\n _map: LuxMapInstance,\n layerRef: React.MutableRefObject<unknown>\n): void {\n if (!layerRef.current) return;\n const ol = (window as unknown as { ol?: OlLike }).ol;\n if (!ol) return;\n // Overlay doesn't have a built-in remove on the overlay itself;\n // set position to undefined to hide it\n (layerRef.current as OlOverlay).setPosition(undefined);\n layerRef.current = null;\n}\n\n// Minimal pin SVG (red teardrop, 30×40)\nconst PIN_SVG = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"30\" height=\"40\" viewBox=\"0 0 30 40\">\n <path d=\"M15 0C7.268 0 1 6.268 1 14c0 10.5 14 26 14 26S29 24.5 29 14C29 6.268 22.732 0 15 0z\"\n fill=\"#e53935\" stroke=\"#b71c1c\" stroke-width=\"1.5\"/>\n <circle cx=\"15\" cy=\"14\" r=\"5\" fill=\"white\"/>\n</svg>`;\n\n// Minimal OL type stubs used only within this file\ninterface OlOverlay {\n setPosition(pos: [number, number] | undefined): void;\n}\n\ninterface OlLike {\n proj?: {\n transform(\n coordinate: [number, number],\n source: string,\n destination: string\n ): [number, number];\n };\n Overlay: new (opts: { element: HTMLElement; positioning: string; stopEvent: boolean }) => OlOverlay;\n}\n\ninterface LuxMapViewWithProjection {\n getProjection?(): { getCode?(): string } | undefined;\n}\n\nexport function convertMapClickCoordinateToLatLon(\n map: LuxMapInstance,\n coordinate: [number, number]\n): LatLon {\n const ol = (window as unknown as { ol?: OlLike }).ol;\n const transform = ol?.proj?.transform;\n\n if (!transform) {\n const [easting, northing] = coordinate;\n return lurefToLatLon(easting, northing);\n }\n\n const sourceProjection =\n (map.getView() as LuxMapViewWithProjection).getProjection?.()?.getCode?.() ??\n DEFAULT_CLICK_SOURCE_PROJECTION;\n\n const [lon, lat] = transform(coordinate, sourceProjection, WGS84_PROJECTION);\n return { lat, lon };\n}\n","import { useState, useEffect, useCallback, useRef } from 'react';\nimport { latLonToLuref } from '../utils/coordinates';\nimport type { LatLon, Address } from '../types';\n\nconst REVERSE_GEOCODE_URL = 'https://api.geoportail.lu/geocoder/reverseGeocode';\n\nexport type ReverseGeocodeState =\n | { status: 'idle'; address: null; error: null }\n | { status: 'loading'; address: null; error: null }\n | { status: 'success'; address: Address; error: null }\n | { status: 'error'; address: null; error: Error };\n\n/**\n * Hook for reverse geocoding: convert a WGS84 lat/lon to a Luxembourg address.\n *\n * Uses the Geoportail REST reverse geocode endpoint — no API key required.\n *\n * @example\n * const { state, lookup } = useReverseGeocode();\n * // ...\n * lookup({ lat: 49.6116, lon: 6.1319 });\n * if (state.status === 'success') console.log(state.address.label);\n */\nexport function useReverseGeocode() {\n const [state, setState] = useState<ReverseGeocodeState>({\n status: 'idle',\n address: null,\n error: null,\n });\n\n const abortRef = useRef<AbortController | null>(null);\n\n useEffect(() => () => { abortRef.current?.abort(); }, []);\n\n const lookup = useCallback(async (position: LatLon) => {\n // Cancel any in-flight request\n abortRef.current?.abort();\n const controller = new AbortController();\n abortRef.current = controller;\n\n setState({ status: 'loading', address: null, error: null });\n\n try {\n const { easting, northing } = latLonToLuref(position.lat, position.lon);\n\n const url = new URL(REVERSE_GEOCODE_URL);\n url.searchParams.set('easting', String(easting));\n url.searchParams.set('northing', String(northing));\n\n const res = await fetch(url.toString(), { signal: controller.signal });\n\n if (!res.ok) {\n throw new Error(`Reverse geocode request failed: ${res.status} ${res.statusText}`);\n }\n\n const data = (await res.json()) as {\n results?: Array<{\n easting: number;\n northing: number;\n name?: string;\n distance?: number;\n }>;\n };\n\n const first = data.results?.[0];\n if (!first) {\n throw new Error('No results returned for this position');\n }\n\n setState({\n status: 'success',\n address: {\n label: first.name ?? '',\n distance: first.distance ?? 0,\n easting: first.easting,\n northing: first.northing,\n },\n error: null,\n });\n } catch (err: unknown) {\n if (err instanceof DOMException && err.name === 'AbortError') return;\n setState({\n status: 'error',\n address: null,\n error: err instanceof Error ? err : new Error(String(err)),\n });\n }\n }, []);\n\n const reset = useCallback(() => {\n abortRef.current?.abort();\n setState({ status: 'idle', address: null, error: null });\n }, []);\n\n return { state, lookup, reset };\n}\n","import { useState, useEffect, useCallback, useRef } from 'react';\nimport { lurefToLatLon } from '../utils/coordinates';\nimport type { GeocodeQuery, LatLon } from '../types';\n\nconst GEOCODE_URL = 'https://apiv3.geoportail.lu/geocode/search';\n\nexport interface GeocodeResultItem {\n latLon: LatLon;\n easting: number;\n northing: number;\n accuracy: number;\n street?: string;\n num?: string;\n zip?: string;\n locality?: string;\n}\n\nexport type GeocodeState =\n | { status: 'idle'; results: null; error: null }\n | { status: 'loading'; results: null; error: null }\n | { status: 'success'; results: GeocodeResultItem[]; error: null }\n | { status: 'error'; results: null; error: Error };\n\n/**\n * Hook for forward geocoding: search for a Luxembourg address and get coordinates.\n *\n * @example\n * const { state, search } = useGeocode();\n * search({ queryString: '1 rue du Fort Thüngen, Luxembourg' });\n * if (state.status === 'success') {\n * const { lat, lon } = state.results[0].latLon;\n * }\n */\nexport function useGeocode() {\n const [state, setState] = useState<GeocodeState>({\n status: 'idle',\n results: null,\n error: null,\n });\n\n const abortRef = useRef<AbortController | null>(null);\n\n useEffect(() => () => { abortRef.current?.abort(); }, []);\n\n const search = useCallback(async (query: GeocodeQuery) => {\n abortRef.current?.abort();\n const controller = new AbortController();\n abortRef.current = controller;\n\n setState({ status: 'loading', results: null, error: null });\n\n try {\n const url = new URL(GEOCODE_URL);\n\n if (query.queryString) {\n url.searchParams.set('queryString', query.queryString);\n } else {\n if (query.num) url.searchParams.set('num', query.num);\n if (query.street) url.searchParams.set('street', query.street);\n if (query.zip) url.searchParams.set('zip', query.zip);\n if (query.locality) url.searchParams.set('locality', query.locality);\n }\n\n const res = await fetch(url.toString(), { signal: controller.signal });\n\n if (!res.ok) {\n throw new Error(`Geocode request failed: ${res.status} ${res.statusText}`);\n }\n\n const data = (await res.json()) as {\n results?: Array<{\n easting: number;\n northing: number;\n accuracy?: number;\n AddressDetails?: {\n street?: string;\n number?: string;\n zip?: string;\n locality?: string;\n };\n }>;\n };\n\n const results: GeocodeResultItem[] = (data.results ?? []).map((r) => ({\n latLon: lurefToLatLon(r.easting, r.northing),\n easting: r.easting,\n northing: r.northing,\n accuracy: r.accuracy ?? 0,\n street: r.AddressDetails?.street,\n num: r.AddressDetails?.number,\n zip: r.AddressDetails?.zip,\n locality: r.AddressDetails?.locality,\n }));\n\n setState({ status: 'success', results, error: null });\n } catch (err: unknown) {\n if (err instanceof DOMException && err.name === 'AbortError') return;\n setState({\n status: 'error',\n results: null,\n error: err instanceof Error ? err : new Error(String(err)),\n });\n }\n }, []);\n\n const reset = useCallback(() => {\n abortRef.current?.abort();\n setState({ status: 'idle', results: null, error: null });\n }, []);\n\n return { state, search, reset };\n}\n"],"names":["LUX_BASE_URL","LUX_PROTOCOL","LUX_I18N_URL","LUX_STYLESHEET_URL","LUX_VENDOR_URL","LUX_API_URL","LUX_STYLESHEET_ID","LUX_VENDOR_SCRIPT_ID","LUX_API_SCRIPT_ID","ELEMENT_STATUS_ATTRIBUTE","loadPromise","loadLuxApi","loadLuxApiInternal","error","pollForLux","resolve","reject","attempts","check","configureLux","loadStylesheetOnce","loadScriptOnce","waitForLux","lux","id","src","existing","waitForElementLoad","script","attachLoadHandlers","href","link","element","resourceUrl","kind","status","onLoad","onError","handleLoad","cleanup","handleError","useLuxApi","state","setState","useState","useEffect","cancelled","err","FE","FN","LON0","LAT0","SCALE","A","F","B","E2","DX","DY","DZ","degToRad","d","radToDeg","r","wgs84ToEd50","lat","lon","latR","lonR","sinLat","cosLat","sinLon","cosLon","aWgs","fWgs","bWgs","e2Wgs","da","df","N","dLat","dLon","ed50ToWgs84","M","tmForward","lon0R","lat0R","tanLat","T","C","dl","XX","meridianArc","M0","easting","northing","tmInverse","x","y","mu","e1","phi1","sinPhi1","cosPhi1","tanPhi1","N1","T1","C1","R1","D","e2","e4","e6","latLonToLuref","ed50","lurefToLatLon","DEFAULT_CLICK_SOURCE_PROJECTION","WGS84_PROJECTION","LUXEMBOURG_CITY","DEFAULT_BG_LAYER","GeoportailMap","forwardRef","center","zoom","bgLayer","markerMode","markerPosition","onMarkerPlace","className","style","layers","ref","luxApi","mapContainerRef","useRef","mapRef","markerLayerRef","clickListenerRef","onMarkerPlaceRef","mapInstance","map","clearMarker","initialPos","placeMarker","handler","args","evt","latLon","convertMapClickCoordinateToLatLon","_a","useImperativeHandle","coords","z","jsx","jsxs","position","layerRef","ol","el","PIN_SVG","overlay","_map","coordinate","transform","sourceProjection","_e","_d","_c","_b","REVERSE_GEOCODE_URL","useReverseGeocode","abortRef","lookup","useCallback","controller","url","res","first","reset","GEOCODE_URL","useGeocode","search","query","results"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dacostafilipe/react-geoportail",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "React SDK for the Geoportail Luxembourg v3 API",
5
5
  "type": "module",
6
6
  "main": "./dist/react-geoportail.umd.cjs",
@@ -21,7 +21,8 @@
21
21
  "build": "tsc -p tsconfig.build.json && vite build",
22
22
  "prepack": "npm run build",
23
23
  "preview": "vite preview",
24
- "type-check": "tsc --noEmit"
24
+ "type-check": "tsc --noEmit",
25
+ "test": "vitest run"
25
26
  },
26
27
  "peerDependencies": {
27
28
  "react": ">=17.0.0",
@@ -33,7 +34,8 @@
33
34
  "@vitejs/plugin-react": "^4.2.0",
34
35
  "typescript": "^5.3.0",
35
36
  "vite": "^5.0.0",
36
- "vite-plugin-dts": "^3.6.0"
37
+ "vite-plugin-dts": "^3.6.0",
38
+ "vitest": "^3.2.4"
37
39
  },
38
40
  "keywords": [
39
41
  "geoportail",