@object-ui/plugin-map 11.3.0 → 11.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # @object-ui/plugin-map
2
2
 
3
+ ## 11.5.0
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [6fffd3d]
8
+ - Updated dependencies [9255686]
9
+ - Updated dependencies [fae75e2]
10
+ - Updated dependencies [1072701]
11
+ - @object-ui/react@11.5.0
12
+ - @object-ui/components@11.5.0
13
+ - @object-ui/types@11.5.0
14
+ - @object-ui/core@11.5.0
15
+
16
+ ## 11.4.0
17
+
18
+ ### Patch Changes
19
+
20
+ - Updated dependencies [8bf6295]
21
+ - Updated dependencies [1948c5b]
22
+ - Updated dependencies [bce581a]
23
+ - Updated dependencies [c38d107]
24
+ - Updated dependencies [7782698]
25
+ - Updated dependencies [e84d64d]
26
+ - @object-ui/types@11.4.0
27
+ - @object-ui/components@11.4.0
28
+ - @object-ui/core@11.4.0
29
+ - @object-ui/react@11.4.0
30
+
3
31
  ## 11.3.0
4
32
 
5
33
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"ObjectMap.d.ts","sourceRoot":"","sources":["../src/ObjectMap.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;;;;GAYG;AAEH,OAAO,KAA4D,MAAM,OAAO,CAAC;AACjF,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAY,MAAM,kBAAkB,CAAC;AAQ/E,OAAO,kCAAkC,CAAC;AAY1C,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,gBAAgB,CAAC;IACzB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;IACtC,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;IACnC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;IAC/B,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;IACjC,8CAA8C;IAC9C,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,6CAA6C;IAC7C,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAwOD,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,cAAc,CA2c9C,CAAC;AAEF,eAAe,SAAS,CAAC"}
1
+ {"version":3,"file":"ObjectMap.d.ts","sourceRoot":"","sources":["../src/ObjectMap.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;;;;GAYG;AAEH,OAAO,KAA4D,MAAM,OAAO,CAAC;AACjF,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAY,MAAM,kBAAkB,CAAC;AAQ/E,OAAO,kCAAkC,CAAC;AAqB1C,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,gBAAgB,CAAC;IACzB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;IACtC,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;IACnC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;IAC/B,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;IACjC,8CAA8C;IAC9C,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,6CAA6C;IAC7C,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAkPD,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,cAAc,CA4d9C,CAAC;AAEF,eAAe,SAAS,CAAC"}
package/dist/index.js CHANGED
@@ -1,22 +1,23 @@
1
1
  import { useCallback as e, useEffect as t, useMemo as n, useRef as r, useState as i } from "react";
2
2
  import { ComponentRegistry as a, buildExpandFields as o, extractRecords as s } from "@object-ui/core";
3
3
  import { useNavigationOverlay as ee, useSchemaContext as c } from "@object-ui/react";
4
- import { NavigationOverlay as te, cn as l, useIsMobile as u } from "@object-ui/components";
5
- import { z as d } from "zod";
6
- import ne, { Marker as f, NavigationControl as re, Popup as p } from "react-map-gl/maplibre";
4
+ import { NavigationOverlay as te, cn as l, useIsMobile as ne } from "@object-ui/components";
5
+ import { z as u } from "zod";
6
+ import d, { Marker as f, NavigationControl as re, Popup as ie } from "react-map-gl/maplibre";
7
7
  import "maplibre-gl/dist/maplibre-gl.css";
8
- import { jsx as m, jsxs as h } from "react/jsx-runtime";
8
+ import { jsx as p, jsxs as m } from "react/jsx-runtime";
9
9
  //#region src/ObjectMap.tsx
10
- var g = d.object({
11
- latitudeField: d.string().optional(),
12
- longitudeField: d.string().optional(),
13
- locationField: d.string().optional(),
14
- titleField: d.string().optional(),
15
- descriptionField: d.string().optional(),
16
- zoom: d.number().optional(),
17
- center: d.tuple([d.number(), d.number()]).optional()
18
- });
19
- function ie(e) {
10
+ var h = u.object({
11
+ latitudeField: u.string().optional(),
12
+ longitudeField: u.string().optional(),
13
+ locationField: u.string().optional(),
14
+ titleField: u.string().optional(),
15
+ descriptionField: u.string().optional(),
16
+ zoom: u.number().optional(),
17
+ center: u.tuple([u.number(), u.number()]).optional(),
18
+ style: u.string().optional()
19
+ }), ae = "https://demotiles.maplibre.org/style.json";
20
+ function g(e) {
20
21
  return e.data ? e.data : e.staticData ? {
21
22
  provider: "value",
22
23
  items: e.staticData
@@ -25,7 +26,7 @@ function ie(e) {
25
26
  object: e.objectName
26
27
  } : null;
27
28
  }
28
- function _(e) {
29
+ function oe(e) {
29
30
  if (e) {
30
31
  if (typeof e == "string") {
31
32
  let t = e.split(" "), n = t[0], r = t[1]?.toLowerCase() === "desc" ? "desc" : "asc";
@@ -34,7 +35,8 @@ function _(e) {
34
35
  if (Array.isArray(e)) return e.reduce((e, t) => (t.field && t.order && (e[t.field] = t.order), e), {});
35
36
  }
36
37
  }
37
- function v(e) {
38
+ function _(e) {
39
+ let t = e.style || e.mapStyle || e.filter?.map?.style || e.map?.style;
38
40
  if (e.locationField || e.latitudeField) return {
39
41
  locationField: e.locationField,
40
42
  latitudeField: e.latitudeField,
@@ -42,12 +44,16 @@ function v(e) {
42
44
  titleField: e.titleField || "name",
43
45
  descriptionField: e.descriptionField,
44
46
  zoom: e.zoom,
45
- center: e.center
47
+ center: e.center,
48
+ style: t
46
49
  };
47
- let t = null;
48
- if (e.filter && typeof e.filter == "object" && "map" in e.filter ? t = e.filter.map : e.map && (t = e.map), t) {
49
- let e = g.safeParse(t);
50
- return e.success || console.warn("[ObjectMap] Invalid map configuration:", e.error.format()), t;
50
+ let n = null;
51
+ if (e.filter && typeof e.filter == "object" && "map" in e.filter ? n = e.filter.map : e.map && (n = e.map), n) {
52
+ let e = h.safeParse(n);
53
+ return e.success || console.warn("[ObjectMap] Invalid map configuration:", e.error.format()), {
54
+ ...n,
55
+ style: n.style || t
56
+ };
51
57
  }
52
58
  return {
53
59
  latitudeField: "latitude",
@@ -56,10 +62,11 @@ function v(e) {
56
62
  titleField: "name",
57
63
  descriptionField: "description",
58
64
  zoom: 10,
59
- center: [0, 0]
65
+ center: [0, 0],
66
+ style: t
60
67
  };
61
68
  }
62
- function y(e, t) {
69
+ function v(e, t) {
63
70
  if (t.latitudeField && t.longitudeField) {
64
71
  let n = e[t.latitudeField], r = e[t.longitudeField];
65
72
  if (typeof n == "number" && typeof r == "number") return [n, r];
@@ -81,7 +88,7 @@ function y(e, t) {
81
88
  }
82
89
  return null;
83
90
  }
84
- function ae(e, t, n = 50) {
91
+ function se(e, t, n = 50) {
85
92
  if (e.length <= 1 || t >= 15) return e.map((e) => ({
86
93
  id: e.id,
87
94
  coordinates: e.coordinates,
@@ -112,20 +119,22 @@ function ae(e, t, n = 50) {
112
119
  }
113
120
  }), a;
114
121
  }
115
- var b = ({ schema: a, dataSource: c, className: d, onMarkerClick: g, onRowClick: b, onEdit: x, onDelete: S, enableClustering: C, clusterRadius: w = 50, ...T }) => {
116
- let [E, D] = i([]), [oe, O] = i(!0), [k, A] = i(null), [j, M] = i(null), [N, P] = i(null), [F, se] = i(""), I = u(), L = r(null), [R, ce] = i(null), [z, B] = i(null), [V, H] = i(!1), U = e(() => {
122
+ var y = ({ schema: a, dataSource: c, className: u, onMarkerClick: h, onRowClick: y, onEdit: b, onDelete: x, enableClustering: S, clusterRadius: C = 50, ...w }) => {
123
+ let [T, E] = i([]), [ce, D] = i(!0), [O, k] = i(null), [A, j] = i(null), [M, N] = i(null), [P, le] = i(""), F = ne(), I = r(null), [L, R] = i(null), [z, B] = i(null), [V, H] = i(!1), [U, ue] = i(null), de = e((e) => {
124
+ ue(e?.error?.message || "Failed to load the map style/tiles.");
125
+ }, []), fe = e(() => {
117
126
  if (typeof navigator > "u" || !navigator.geolocation) {
118
127
  B("Geolocation is not available in this browser.");
119
128
  return;
120
129
  }
121
130
  H(!0), B(null), navigator.geolocation.getCurrentPosition((e) => {
122
131
  let { longitude: t, latitude: n } = e.coords;
123
- ce({
132
+ R({
124
133
  lng: t,
125
134
  lat: n
126
135
  }), H(!1);
127
136
  try {
128
- L.current?.flyTo({
137
+ I.current?.flyTo({
129
138
  center: [t, n],
130
139
  zoom: 12,
131
140
  duration: 800
@@ -138,40 +147,40 @@ var b = ({ schema: a, dataSource: c, className: d, onMarkerClick: g, onRowClick:
138
147
  timeout: 8e3,
139
148
  maximumAge: 6e4
140
149
  });
141
- }, []), W = ie(a), G = n(() => W, [JSON.stringify(W)]), K = v(a), q = G?.provider === "value";
150
+ }, []), W = g(a), G = n(() => W, [JSON.stringify(W)]), K = _(a), q = G?.provider === "value";
142
151
  t(() => {
143
152
  (async () => {
144
153
  try {
145
- if (O(!0), T.data) {
146
- let e = T.data;
154
+ if (D(!0), w.data) {
155
+ let e = w.data;
147
156
  if (Array.isArray(e)) {
148
- D(e), O(!1);
157
+ E(e), D(!1);
149
158
  return;
150
159
  }
151
160
  }
152
161
  if (a.data) {
153
162
  let e = a.data;
154
163
  if (Array.isArray(e)) {
155
- D(e), O(!1);
164
+ E(e), D(!1);
156
165
  return;
157
166
  }
158
167
  }
159
168
  if (q && G?.provider === "value") {
160
- D(G.items), O(!1);
169
+ E(G.items), D(!1);
161
170
  return;
162
171
  }
163
172
  if (!c || typeof c.find != "function") throw Error("DataSource required for object/api providers");
164
173
  if (G?.provider === "object") {
165
- let e = G.object, t = o(j?.fields);
166
- D(s(await c.find(e, {
174
+ let e = G.object, t = o(A?.fields);
175
+ E(s(await c.find(e, {
167
176
  $filter: a.filter,
168
- $orderby: _(a.sort),
177
+ $orderby: oe(a.sort),
169
178
  ...t.length > 0 ? { $expand: t } : {}
170
179
  })));
171
- } else G?.provider === "api" && (console.warn("API provider not yet implemented for ObjectMap"), D([]));
172
- O(!1);
180
+ } else G?.provider === "api" && (console.warn("API provider not yet implemented for ObjectMap"), E([]));
181
+ D(!1);
173
182
  } catch (e) {
174
- A(e), O(!1);
183
+ k(e), D(!1);
175
184
  }
176
185
  })();
177
186
  }, [
@@ -180,14 +189,14 @@ var b = ({ schema: a, dataSource: c, className: d, onMarkerClick: g, onRowClick:
180
189
  q,
181
190
  a.filter,
182
191
  a.sort,
183
- j
192
+ A
184
193
  ]), t(() => {
185
194
  !q && c && (async () => {
186
195
  try {
187
196
  if (!c) return;
188
197
  let e = G?.provider === "object" ? G.object : a.objectName;
189
198
  if (!e) return;
190
- M(await c.getObjectSchema(e));
199
+ j(await c.getObjectSchema(e));
191
200
  } catch (e) {
192
201
  console.error("Failed to fetch object schema:", e);
193
202
  }
@@ -201,8 +210,8 @@ var b = ({ schema: a, dataSource: c, className: d, onMarkerClick: g, onRowClick:
201
210
  let { markers: J, invalidCount: Y } = n(() => {
202
211
  let e = 0;
203
212
  return {
204
- markers: E.map((t, n) => {
205
- let r = y(t, K);
213
+ markers: T.map((t, n) => {
214
+ let r = v(t, K);
206
215
  if (!r) return e++, null;
207
216
  let i = K.titleField ? t[K.titleField] : "Marker", a = K.descriptionField ? t[K.descriptionField] : void 0, [o, s] = r;
208
217
  return !isFinite(o) || !isFinite(s) || o < -90 || o > 90 || s < -180 || s > 180 ? (e++, null) : {
@@ -215,15 +224,15 @@ var b = ({ schema: a, dataSource: c, className: d, onMarkerClick: g, onRowClick:
215
224
  }).filter((e) => e !== null),
216
225
  invalidCount: e
217
226
  };
218
- }, [E, K]), X = n(() => J.find((e) => e.id === N), [J, N]), [Z, le] = i(K.zoom || 3), Q = ee({
227
+ }, [T, K]), X = n(() => J.find((e) => e.id === M), [J, M]), [Z, pe] = i(K.zoom || 3), Q = ee({
219
228
  navigation: a.navigation,
220
229
  objectName: a.objectName,
221
- onRowClick: b
230
+ onRowClick: y
222
231
  }), $ = n(() => {
223
- if (!F.trim()) return J;
224
- let e = F.toLowerCase();
232
+ if (!P.trim()) return J;
233
+ let e = P.toLowerCase();
225
234
  return J.filter((t) => t.title?.toLowerCase().includes(e) || t.description?.toLowerCase().includes(e));
226
- }, [J, F]), ue = n(() => C ?? (a.enableClustering || $.length > 100) ? ae($, Z, w) : $.map((e) => ({
235
+ }, [J, P]), me = n(() => S ?? (a.enableClustering || $.length > 100) ? se($, Z, C) : $.map((e) => ({
227
236
  id: e.id,
228
237
  coordinates: e.coordinates,
229
238
  markers: [e],
@@ -231,10 +240,10 @@ var b = ({ schema: a, dataSource: c, className: d, onMarkerClick: g, onRowClick:
231
240
  })), [
232
241
  $,
233
242
  Z,
243
+ S,
234
244
  C,
235
- w,
236
245
  a
237
- ]), de = n(() => {
246
+ ]), he = n(() => {
238
247
  if (!$.length) return {
239
248
  longitude: K.center?.[1] || 0,
240
249
  latitude: K.center?.[0] || 0,
@@ -247,87 +256,99 @@ var b = ({ schema: a, dataSource: c, className: d, onMarkerClick: g, onRowClick:
247
256
  zoom: K.zoom || 3
248
257
  };
249
258
  }, [$, K]);
250
- return oe ? /* @__PURE__ */ m("div", {
251
- className: l("min-w-0 overflow-hidden", d),
252
- children: /* @__PURE__ */ m("div", {
259
+ return ce ? /* @__PURE__ */ p("div", {
260
+ className: l("min-w-0 overflow-hidden", u),
261
+ children: /* @__PURE__ */ p("div", {
253
262
  className: "flex items-center justify-center h-96 bg-muted rounded-lg border",
254
- children: /* @__PURE__ */ m("div", {
263
+ children: /* @__PURE__ */ p("div", {
255
264
  className: "text-muted-foreground",
256
265
  children: "Loading map..."
257
266
  })
258
267
  })
259
- }) : k ? /* @__PURE__ */ m("div", {
260
- className: l("min-w-0 overflow-hidden", d),
261
- children: /* @__PURE__ */ m("div", {
268
+ }) : O ? /* @__PURE__ */ p("div", {
269
+ className: l("min-w-0 overflow-hidden", u),
270
+ children: /* @__PURE__ */ p("div", {
262
271
  className: "flex items-center justify-center h-96 bg-muted rounded-lg border",
263
- children: /* @__PURE__ */ h("div", {
272
+ children: /* @__PURE__ */ m("div", {
264
273
  className: "text-destructive",
265
- children: ["Error: ", k.message]
274
+ children: ["Error: ", O.message]
266
275
  })
267
276
  })
268
- }) : /* @__PURE__ */ h("div", {
269
- className: l("min-w-0 overflow-hidden", d),
277
+ }) : /* @__PURE__ */ m("div", {
278
+ className: l("min-w-0 overflow-hidden", u),
270
279
  children: [
271
- Y > 0 && /* @__PURE__ */ m("div", {
280
+ Y > 0 && /* @__PURE__ */ p("div", {
272
281
  className: "mb-2 p-2 text-sm text-yellow-800 bg-yellow-50 border border-yellow-200 rounded",
273
282
  children: `${Y} record${Y === 1 ? "" : "s"} with missing or invalid coordinates excluded from the map.`
274
283
  }),
275
- J.length > 0 && /* @__PURE__ */ m("div", {
284
+ J.length > 0 && /* @__PURE__ */ p("div", {
276
285
  className: "mb-2",
277
- children: /* @__PURE__ */ m("input", {
286
+ children: /* @__PURE__ */ p("input", {
278
287
  type: "text",
279
- value: F,
280
- onChange: (e) => se(e.target.value),
288
+ value: P,
289
+ onChange: (e) => le(e.target.value),
281
290
  placeholder: "Search locations…",
282
291
  className: "w-full px-3 py-2 text-sm border rounded-md bg-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring"
283
292
  })
284
293
  }),
285
- /* @__PURE__ */ h("div", {
294
+ /* @__PURE__ */ m("div", {
286
295
  className: "relative border rounded-lg overflow-hidden bg-muted h-[300px] sm:h-[400px] md:h-[500px] lg:h-[600px] w-full",
287
296
  children: [
288
- /* @__PURE__ */ h(ne, {
297
+ /* @__PURE__ */ m(d, {
289
298
  ref: (e) => {
290
- L.current = e;
299
+ I.current = e;
291
300
  },
292
- initialViewState: de,
301
+ initialViewState: he,
293
302
  style: {
294
303
  width: "100%",
295
304
  height: "100%"
296
305
  },
297
- mapStyle: "https://demotiles.maplibre.org/style.json",
306
+ mapStyle: K.style || ae,
298
307
  touchZoomRotate: !0,
299
308
  dragRotate: !0,
300
309
  touchPitch: !0,
301
- onZoom: (e) => le(Math.round(e.viewState.zoom)),
310
+ onZoom: (e) => pe(Math.round(e.viewState.zoom)),
311
+ onError: de,
302
312
  children: [
303
- /* @__PURE__ */ m(re, {
313
+ U && /* @__PURE__ */ m("div", {
314
+ role: "alert",
315
+ className: "absolute inset-x-0 top-0 z-20 p-2 text-sm text-center text-amber-900 bg-amber-50 border-b border-amber-200",
316
+ children: [
317
+ "Map failed to load (",
318
+ U,
319
+ "). Markers below are still listed in the search box;",
320
+ " ",
321
+ K.style ? "check the configured map style URL." : "configure a custom map style for production use."
322
+ ]
323
+ }),
324
+ /* @__PURE__ */ p(re, {
304
325
  position: "top-right",
305
326
  showCompass: !0,
306
327
  showZoom: !0
307
328
  }),
308
- /* @__PURE__ */ m("button", {
329
+ /* @__PURE__ */ p("button", {
309
330
  type: "button",
310
- onClick: U,
331
+ onClick: fe,
311
332
  disabled: V,
312
333
  className: "absolute top-2 left-2 z-10 inline-flex items-center justify-center size-9 rounded-md bg-background/95 border shadow-sm hover:bg-background disabled:opacity-50",
313
334
  "aria-label": "Show my location",
314
335
  "data-testid": "map-geolocate",
315
- children: /* @__PURE__ */ m("span", {
336
+ children: /* @__PURE__ */ p("span", {
316
337
  "aria-hidden": "true",
317
338
  children: V ? "⏳" : "🧭"
318
339
  })
319
340
  }),
320
- R && /* @__PURE__ */ m(f, {
321
- longitude: R.lng,
322
- latitude: R.lat,
341
+ L && /* @__PURE__ */ p(f, {
342
+ longitude: L.lng,
343
+ latitude: L.lat,
323
344
  anchor: "center",
324
- children: /* @__PURE__ */ m("div", {
345
+ children: /* @__PURE__ */ p("div", {
325
346
  className: "size-3 rounded-full bg-blue-500 ring-4 ring-blue-500/30 shadow",
326
347
  "aria-label": "Your location",
327
348
  "data-testid": "map-user-location"
328
349
  })
329
350
  }),
330
- ue.map((e) => e.isCluster ? /* @__PURE__ */ m(f, {
351
+ me.map((e) => e.isCluster ? /* @__PURE__ */ p(f, {
331
352
  longitude: e.coordinates[0],
332
353
  latitude: e.coordinates[1],
333
354
  anchor: "center",
@@ -335,14 +356,14 @@ var b = ({ schema: a, dataSource: c, className: d, onMarkerClick: g, onRowClick:
335
356
  t.originalEvent.stopPropagation();
336
357
  try {
337
358
  let t = Math.min(20, Math.max(Z + 2, 8));
338
- L.current?.flyTo({
359
+ I.current?.flyTo({
339
360
  center: [e.coordinates[0], e.coordinates[1]],
340
361
  zoom: t,
341
362
  duration: 600
342
363
  });
343
364
  } catch {}
344
365
  },
345
- children: /* @__PURE__ */ m("div", {
366
+ children: /* @__PURE__ */ p("div", {
346
367
  className: "flex items-center justify-center rounded-full bg-primary text-primary-foreground font-bold text-xs cursor-pointer hover:scale-110 transition-transform shadow-md",
347
368
  style: {
348
369
  width: Math.min(48, 24 + e.markers.length * 2),
@@ -352,46 +373,46 @@ var b = ({ schema: a, dataSource: c, className: d, onMarkerClick: g, onRowClick:
352
373
  "data-testid": "map-cluster",
353
374
  children: e.markers.length
354
375
  })
355
- }, e.id) : /* @__PURE__ */ m(f, {
376
+ }, e.id) : /* @__PURE__ */ p(f, {
356
377
  longitude: e.coordinates[0],
357
378
  latitude: e.coordinates[1],
358
379
  anchor: "bottom",
359
380
  onClick: (t) => {
360
381
  t.originalEvent.stopPropagation();
361
382
  let n = e.markers[0];
362
- P(n.id), Q.handleClick(n.data), g?.(n.data);
383
+ N(n.id), Q.handleClick(n.data), h?.(n.data);
363
384
  },
364
- children: /* @__PURE__ */ m("div", {
385
+ children: /* @__PURE__ */ p("div", {
365
386
  className: "text-2xl cursor-pointer hover:scale-110 transition-transform",
366
387
  children: "📍"
367
388
  })
368
389
  }, e.id)),
369
- X && !I && /* @__PURE__ */ m(p, {
390
+ X && !F && /* @__PURE__ */ p(ie, {
370
391
  longitude: X.coordinates[0],
371
392
  latitude: X.coordinates[1],
372
393
  anchor: "top",
373
- onClose: () => P(null),
394
+ onClose: () => N(null),
374
395
  closeOnClick: !1,
375
- children: /* @__PURE__ */ h("div", {
396
+ children: /* @__PURE__ */ m("div", {
376
397
  className: "p-2 min-w-[150px] sm:min-w-[200px]",
377
398
  children: [
378
- /* @__PURE__ */ m("h3", {
399
+ /* @__PURE__ */ p("h3", {
379
400
  className: "font-bold text-sm mb-1",
380
401
  children: X.title
381
402
  }),
382
- X.description && /* @__PURE__ */ m("p", {
403
+ X.description && /* @__PURE__ */ p("p", {
383
404
  className: "text-xs text-muted-foreground",
384
405
  children: X.description
385
406
  }),
386
- /* @__PURE__ */ h("div", {
407
+ /* @__PURE__ */ m("div", {
387
408
  className: "mt-2 text-xs flex gap-2",
388
- children: [x && /* @__PURE__ */ m("button", {
409
+ children: [b && /* @__PURE__ */ p("button", {
389
410
  className: "text-blue-500 hover:underline",
390
- onClick: () => x(X.data),
411
+ onClick: () => b(X.data),
391
412
  children: "Edit"
392
- }), S && /* @__PURE__ */ m("button", {
413
+ }), x && /* @__PURE__ */ p("button", {
393
414
  className: "text-red-500 hover:underline",
394
- onClick: () => S(X.data),
415
+ onClick: () => x(X.data),
395
416
  children: "Delete"
396
417
  })]
397
418
  })
@@ -400,67 +421,67 @@ var b = ({ schema: a, dataSource: c, className: d, onMarkerClick: g, onRowClick:
400
421
  })
401
422
  ]
402
423
  }),
403
- X && I && /* @__PURE__ */ h("div", {
424
+ X && F && /* @__PURE__ */ m("div", {
404
425
  className: "absolute inset-x-0 bottom-0 z-30 bg-background border-t shadow-lg rounded-t-2xl p-4 pb-[max(env(safe-area-inset-bottom),1rem)]",
405
426
  role: "dialog",
406
427
  "aria-label": "Location details",
407
428
  "data-testid": "map-mobile-record-sheet",
408
429
  children: [
409
- /* @__PURE__ */ m("div", {
430
+ /* @__PURE__ */ p("div", {
410
431
  className: "mx-auto mb-2 h-1 w-10 rounded-full bg-muted",
411
432
  "aria-hidden": "true"
412
433
  }),
413
- /* @__PURE__ */ h("div", {
434
+ /* @__PURE__ */ m("div", {
414
435
  className: "flex items-start justify-between gap-3",
415
- children: [/* @__PURE__ */ h("div", {
436
+ children: [/* @__PURE__ */ m("div", {
416
437
  className: "min-w-0 flex-1",
417
- children: [/* @__PURE__ */ m("h3", {
438
+ children: [/* @__PURE__ */ p("h3", {
418
439
  className: "text-sm font-semibold truncate",
419
440
  children: X.title
420
- }), X.description && /* @__PURE__ */ m("p", {
441
+ }), X.description && /* @__PURE__ */ p("p", {
421
442
  className: "mt-1 text-xs text-muted-foreground line-clamp-3",
422
443
  children: X.description
423
444
  })]
424
- }), /* @__PURE__ */ m("button", {
445
+ }), /* @__PURE__ */ p("button", {
425
446
  type: "button",
426
- onClick: () => P(null),
447
+ onClick: () => N(null),
427
448
  className: "text-muted-foreground hover:text-foreground text-lg leading-none px-2",
428
449
  "aria-label": "Close details",
429
450
  "data-testid": "map-mobile-record-close",
430
451
  children: "×"
431
452
  })]
432
453
  }),
433
- /* @__PURE__ */ h("div", {
454
+ /* @__PURE__ */ m("div", {
434
455
  className: "mt-3 flex flex-wrap gap-2 text-xs",
435
- children: [x && /* @__PURE__ */ m("button", {
456
+ children: [b && /* @__PURE__ */ p("button", {
436
457
  className: "px-3 py-1.5 rounded-md border bg-card hover:bg-accent",
437
- onClick: () => x(X.data),
458
+ onClick: () => b(X.data),
438
459
  children: "Edit"
439
- }), S && /* @__PURE__ */ m("button", {
460
+ }), x && /* @__PURE__ */ p("button", {
440
461
  className: "px-3 py-1.5 rounded-md border border-destructive/30 text-destructive hover:bg-destructive/10",
441
- onClick: () => S(X.data),
462
+ onClick: () => x(X.data),
442
463
  children: "Delete"
443
464
  })]
444
465
  })
445
466
  ]
446
467
  }),
447
- z && /* @__PURE__ */ m("div", {
468
+ z && /* @__PURE__ */ p("div", {
448
469
  className: "absolute top-2 left-14 right-2 z-10 text-xs px-3 py-1.5 rounded-md bg-destructive/10 text-destructive border border-destructive/30",
449
470
  children: z
450
471
  })
451
472
  ]
452
473
  }),
453
- Q.isOverlay && /* @__PURE__ */ m(te, {
474
+ Q.isOverlay && /* @__PURE__ */ p(te, {
454
475
  ...Q,
455
476
  title: "Location Details",
456
- children: (e) => /* @__PURE__ */ m("div", {
477
+ children: (e) => /* @__PURE__ */ p("div", {
457
478
  className: "space-y-3",
458
- children: Object.entries(e).map(([e, t]) => /* @__PURE__ */ h("div", {
479
+ children: Object.entries(e).map(([e, t]) => /* @__PURE__ */ m("div", {
459
480
  className: "flex flex-col",
460
- children: [/* @__PURE__ */ m("span", {
481
+ children: [/* @__PURE__ */ p("span", {
461
482
  className: "text-xs font-medium text-muted-foreground uppercase tracking-wide",
462
483
  children: e.replace(/_/g, " ")
463
- }), /* @__PURE__ */ m("span", {
484
+ }), /* @__PURE__ */ p("span", {
464
485
  className: "text-sm",
465
486
  children: String(t ?? "—")
466
487
  })]
@@ -469,15 +490,15 @@ var b = ({ schema: a, dataSource: c, className: d, onMarkerClick: g, onRowClick:
469
490
  })
470
491
  ]
471
492
  });
472
- }, x = ({ schema: e, ...t }) => {
493
+ }, b = ({ schema: e, ...t }) => {
473
494
  let { dataSource: n } = c() || {};
474
- return /* @__PURE__ */ m(b, {
495
+ return /* @__PURE__ */ p(y, {
475
496
  schema: e,
476
497
  dataSource: n,
477
498
  ...t
478
499
  });
479
500
  };
480
- console.log("Registering object-map..."), a.register("object-map", x, {
501
+ console.log("Registering object-map..."), a.register("object-map", b, {
481
502
  namespace: "plugin-map",
482
503
  label: "Object Map",
483
504
  category: "view",
@@ -492,7 +513,7 @@ console.log("Registering object-map..."), a.register("object-map", x, {
492
513
  label: "Map Config",
493
514
  description: "latitudeField, longitudeField, titleField"
494
515
  }]
495
- }), a.register("map", x, {
516
+ }), a.register("map", b, {
496
517
  namespace: "view",
497
518
  label: "Map View",
498
519
  category: "view",
@@ -509,4 +530,4 @@ console.log("Registering object-map..."), a.register("object-map", x, {
509
530
  }]
510
531
  });
511
532
  //#endregion
512
- export { b as ObjectMap, x as ObjectMapRenderer };
533
+ export { y as ObjectMap, b as ObjectMapRenderer };
@@ -1 +1 @@
1
- (function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require("react"),require("@object-ui/core"),require("@object-ui/react"),require("@object-ui/components"),require("zod"),require("react-map-gl/maplibre"),require("maplibre-gl/dist/maplibre-gl.css"),require("react/jsx-runtime")):typeof define==`function`&&define.amd?define([`exports`,`react`,`@object-ui/core`,`@object-ui/react`,`@object-ui/components`,`zod`,`react-map-gl/maplibre`,`maplibre-gl/dist/maplibre-gl.css`,`react/jsx-runtime`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.ObjectUIPluginMap={},e.React,e.ObjectUICore,e.ObjectUIReact,e.ObjectUIComponents,e.zod,e.react_map_gl_maplibre,e.maplibre_gl_dist_maplibre_gl_css,e.react_jsx_runtime))})(this,function(e,t,n,r,i,a,o,s,c){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var l=Object.create,u=Object.defineProperty,d=Object.getOwnPropertyDescriptor,f=Object.getOwnPropertyNames,p=Object.getPrototypeOf,m=Object.prototype.hasOwnProperty,h=(e,t,n,r)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var i=f(t),a=0,o=i.length,s;a<o;a++)s=i[a],!m.call(e,s)&&s!==n&&u(e,s,{get:(e=>t[e]).bind(null,s),enumerable:!(r=d(t,s))||r.enumerable});return e},g=(e,t,n)=>(n=e==null?{}:l(p(e)),h(t||!e||!e.__esModule?u(n,`default`,{value:e,enumerable:!0}):n,e));t=g(t,1),o=g(o,1);var _=a.z.object({latitudeField:a.z.string().optional(),longitudeField:a.z.string().optional(),locationField:a.z.string().optional(),titleField:a.z.string().optional(),descriptionField:a.z.string().optional(),zoom:a.z.number().optional(),center:a.z.tuple([a.z.number(),a.z.number()]).optional()});function v(e){return e.data?e.data:e.staticData?{provider:`value`,items:e.staticData}:e.objectName?{provider:`object`,object:e.objectName}:null}function y(e){if(e){if(typeof e==`string`){let t=e.split(` `),n=t[0],r=t[1]?.toLowerCase()===`desc`?`desc`:`asc`;return{[n]:r}}if(Array.isArray(e))return e.reduce((e,t)=>(t.field&&t.order&&(e[t.field]=t.order),e),{})}}function b(e){if(e.locationField||e.latitudeField)return{locationField:e.locationField,latitudeField:e.latitudeField,longitudeField:e.longitudeField,titleField:e.titleField||`name`,descriptionField:e.descriptionField,zoom:e.zoom,center:e.center};let t=null;if(e.filter&&typeof e.filter==`object`&&`map`in e.filter?t=e.filter.map:e.map&&(t=e.map),t){let e=_.safeParse(t);return e.success||console.warn(`[ObjectMap] Invalid map configuration:`,e.error.format()),t}return{latitudeField:`latitude`,longitudeField:`longitude`,locationField:`location`,titleField:`name`,descriptionField:`description`,zoom:10,center:[0,0]}}function x(e,t){if(t.latitudeField&&t.longitudeField){let n=e[t.latitudeField],r=e[t.longitudeField];if(typeof n==`number`&&typeof r==`number`)return[n,r]}if(t.locationField){let n=e[t.locationField];if(typeof n==`object`&&n){let e=n.lat||n.latitude,t=n.lng||n.lon||n.longitude;if(typeof e==`number`&&typeof t==`number`)return[e,t]}if(typeof n==`string`){let e=n.split(`,`).map(e=>parseFloat(e.trim()));if(e.length===2&&!isNaN(e[0])&&!isNaN(e[1]))return[e[0],e[1]]}if(Array.isArray(n)&&n.length===2){let e=parseFloat(n[0]),t=parseFloat(n[1]);if(!isNaN(e)&&!isNaN(t))return[e,t]}}return null}function S(e,t,n=50){if(e.length<=1||t>=15)return e.map(e=>({id:e.id,coordinates:e.coordinates,markers:[e],isCluster:!1}));let r=n/2**t,i=new Map;e.forEach(e=>{let t=`${Math.floor(e.coordinates[0]/r)}:${Math.floor(e.coordinates[1]/r)}`;i.has(t)||i.set(t,[]),i.get(t).push(e)});let a=[];return i.forEach((e,t)=>{if(e.length===1)a.push({id:e[0].id,coordinates:e[0].coordinates,markers:e,isCluster:!1});else{let n=e.reduce((e,t)=>e+t.coordinates[0],0)/e.length,r=e.reduce((e,t)=>e+t.coordinates[1],0)/e.length;a.push({id:`cluster-${t}`,coordinates:[n,r],markers:e,isCluster:!0})}}),a}var C=({schema:e,dataSource:a,className:s,onMarkerClick:l,onRowClick:u,onEdit:d,onDelete:f,enableClustering:p,clusterRadius:m=50,...h})=>{let[g,_]=(0,t.useState)([]),[C,w]=(0,t.useState)(!0),[T,E]=(0,t.useState)(null),[D,O]=(0,t.useState)(null),[k,A]=(0,t.useState)(null),[j,M]=(0,t.useState)(``),N=(0,i.useIsMobile)(),P=(0,t.useRef)(null),[F,I]=(0,t.useState)(null),[L,R]=(0,t.useState)(null),[z,B]=(0,t.useState)(!1),V=(0,t.useCallback)(()=>{if(typeof navigator>`u`||!navigator.geolocation){R(`Geolocation is not available in this browser.`);return}B(!0),R(null),navigator.geolocation.getCurrentPosition(e=>{let{longitude:t,latitude:n}=e.coords;I({lng:t,lat:n}),B(!1);try{P.current?.flyTo({center:[t,n],zoom:12,duration:800})}catch{}},e=>{B(!1),R(e.message||`Unable to retrieve location.`)},{enableHighAccuracy:!1,timeout:8e3,maximumAge:6e4})},[]),H=v(e),U=(0,t.useMemo)(()=>H,[JSON.stringify(H)]),W=b(e),G=U?.provider===`value`;(0,t.useEffect)(()=>{(async()=>{try{if(w(!0),h.data){let e=h.data;if(Array.isArray(e)){_(e),w(!1);return}}if(e.data){let t=e.data;if(Array.isArray(t)){_(t),w(!1);return}}if(G&&U?.provider===`value`){_(U.items),w(!1);return}if(!a||typeof a.find!=`function`)throw Error(`DataSource required for object/api providers`);if(U?.provider===`object`){let t=U.object,r=(0,n.buildExpandFields)(D?.fields);_((0,n.extractRecords)(await a.find(t,{$filter:e.filter,$orderby:y(e.sort),...r.length>0?{$expand:r}:{}})))}else U?.provider===`api`&&(console.warn(`API provider not yet implemented for ObjectMap`),_([]));w(!1)}catch(e){E(e),w(!1)}})()},[U,a,G,e.filter,e.sort,D]),(0,t.useEffect)(()=>{!G&&a&&(async()=>{try{if(!a)return;let t=U?.provider===`object`?U.object:e.objectName;if(!t)return;O(await a.getObjectSchema(t))}catch(e){console.error(`Failed to fetch object schema:`,e)}})()},[e.objectName,a,G,U]);let{markers:K,invalidCount:q}=(0,t.useMemo)(()=>{let e=0;return{markers:g.map((t,n)=>{let r=x(t,W);if(!r)return e++,null;let i=W.titleField?t[W.titleField]:`Marker`,a=W.descriptionField?t[W.descriptionField]:void 0,[o,s]=r;return!isFinite(o)||!isFinite(s)||o<-90||o>90||s<-180||s>180?(e++,null):{id:t.id||t._id||`marker-${n}`,title:i,description:a,coordinates:[s,o],data:t}}).filter(e=>e!==null),invalidCount:e}},[g,W]),J=(0,t.useMemo)(()=>K.find(e=>e.id===k),[K,k]),[Y,X]=(0,t.useState)(W.zoom||3),Z=(0,r.useNavigationOverlay)({navigation:e.navigation,objectName:e.objectName,onRowClick:u}),Q=(0,t.useMemo)(()=>{if(!j.trim())return K;let e=j.toLowerCase();return K.filter(t=>t.title?.toLowerCase().includes(e)||t.description?.toLowerCase().includes(e))},[K,j]),$=(0,t.useMemo)(()=>p??(e.enableClustering||Q.length>100)?S(Q,Y,m):Q.map(e=>({id:e.id,coordinates:e.coordinates,markers:[e],isCluster:!1})),[Q,Y,p,m,e]),ee=(0,t.useMemo)(()=>{if(!Q.length)return{longitude:W.center?.[1]||0,latitude:W.center?.[0]||0,zoom:W.zoom||2};let e=Q.map(e=>e.coordinates[0]),t=Q.map(e=>e.coordinates[1]),n=Math.min(...e),r=Math.max(...e),i=Math.min(...t),a=Math.max(...t);return{longitude:(n+r)/2,latitude:(i+a)/2,zoom:W.zoom||3}},[Q,W]);return C?(0,c.jsx)(`div`,{className:(0,i.cn)(`min-w-0 overflow-hidden`,s),children:(0,c.jsx)(`div`,{className:`flex items-center justify-center h-96 bg-muted rounded-lg border`,children:(0,c.jsx)(`div`,{className:`text-muted-foreground`,children:`Loading map...`})})}):T?(0,c.jsx)(`div`,{className:(0,i.cn)(`min-w-0 overflow-hidden`,s),children:(0,c.jsx)(`div`,{className:`flex items-center justify-center h-96 bg-muted rounded-lg border`,children:(0,c.jsxs)(`div`,{className:`text-destructive`,children:[`Error: `,T.message]})})}):(0,c.jsxs)(`div`,{className:(0,i.cn)(`min-w-0 overflow-hidden`,s),children:[q>0&&(0,c.jsx)(`div`,{className:`mb-2 p-2 text-sm text-yellow-800 bg-yellow-50 border border-yellow-200 rounded`,children:`${q} record${q===1?``:`s`} with missing or invalid coordinates excluded from the map.`}),K.length>0&&(0,c.jsx)(`div`,{className:`mb-2`,children:(0,c.jsx)(`input`,{type:`text`,value:j,onChange:e=>M(e.target.value),placeholder:`Search locations…`,className:`w-full px-3 py-2 text-sm border rounded-md bg-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring`})}),(0,c.jsxs)(`div`,{className:`relative border rounded-lg overflow-hidden bg-muted h-[300px] sm:h-[400px] md:h-[500px] lg:h-[600px] w-full`,children:[(0,c.jsxs)(o.default,{ref:e=>{P.current=e},initialViewState:ee,style:{width:`100%`,height:`100%`},mapStyle:`https://demotiles.maplibre.org/style.json`,touchZoomRotate:!0,dragRotate:!0,touchPitch:!0,onZoom:e=>X(Math.round(e.viewState.zoom)),children:[(0,c.jsx)(o.NavigationControl,{position:`top-right`,showCompass:!0,showZoom:!0}),(0,c.jsx)(`button`,{type:`button`,onClick:V,disabled:z,className:`absolute top-2 left-2 z-10 inline-flex items-center justify-center size-9 rounded-md bg-background/95 border shadow-sm hover:bg-background disabled:opacity-50`,"aria-label":`Show my location`,"data-testid":`map-geolocate`,children:(0,c.jsx)(`span`,{"aria-hidden":`true`,children:z?`⏳`:`🧭`})}),F&&(0,c.jsx)(o.Marker,{longitude:F.lng,latitude:F.lat,anchor:`center`,children:(0,c.jsx)(`div`,{className:`size-3 rounded-full bg-blue-500 ring-4 ring-blue-500/30 shadow`,"aria-label":`Your location`,"data-testid":`map-user-location`})}),$.map(e=>e.isCluster?(0,c.jsx)(o.Marker,{longitude:e.coordinates[0],latitude:e.coordinates[1],anchor:`center`,onClick:t=>{t.originalEvent.stopPropagation();try{let t=Math.min(20,Math.max(Y+2,8));P.current?.flyTo({center:[e.coordinates[0],e.coordinates[1]],zoom:t,duration:600})}catch{}},children:(0,c.jsx)(`div`,{className:`flex items-center justify-center rounded-full bg-primary text-primary-foreground font-bold text-xs cursor-pointer hover:scale-110 transition-transform shadow-md`,style:{width:Math.min(48,24+e.markers.length*2),height:Math.min(48,24+e.markers.length*2)},title:`${e.markers.length} markers`,"data-testid":`map-cluster`,children:e.markers.length})},e.id):(0,c.jsx)(o.Marker,{longitude:e.coordinates[0],latitude:e.coordinates[1],anchor:`bottom`,onClick:t=>{t.originalEvent.stopPropagation();let n=e.markers[0];A(n.id),Z.handleClick(n.data),l?.(n.data)},children:(0,c.jsx)(`div`,{className:`text-2xl cursor-pointer hover:scale-110 transition-transform`,children:`📍`})},e.id)),J&&!N&&(0,c.jsx)(o.Popup,{longitude:J.coordinates[0],latitude:J.coordinates[1],anchor:`top`,onClose:()=>A(null),closeOnClick:!1,children:(0,c.jsxs)(`div`,{className:`p-2 min-w-[150px] sm:min-w-[200px]`,children:[(0,c.jsx)(`h3`,{className:`font-bold text-sm mb-1`,children:J.title}),J.description&&(0,c.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:J.description}),(0,c.jsxs)(`div`,{className:`mt-2 text-xs flex gap-2`,children:[d&&(0,c.jsx)(`button`,{className:`text-blue-500 hover:underline`,onClick:()=>d(J.data),children:`Edit`}),f&&(0,c.jsx)(`button`,{className:`text-red-500 hover:underline`,onClick:()=>f(J.data),children:`Delete`})]})]})})]}),J&&N&&(0,c.jsxs)(`div`,{className:`absolute inset-x-0 bottom-0 z-30 bg-background border-t shadow-lg rounded-t-2xl p-4 pb-[max(env(safe-area-inset-bottom),1rem)]`,role:`dialog`,"aria-label":`Location details`,"data-testid":`map-mobile-record-sheet`,children:[(0,c.jsx)(`div`,{className:`mx-auto mb-2 h-1 w-10 rounded-full bg-muted`,"aria-hidden":`true`}),(0,c.jsxs)(`div`,{className:`flex items-start justify-between gap-3`,children:[(0,c.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,c.jsx)(`h3`,{className:`text-sm font-semibold truncate`,children:J.title}),J.description&&(0,c.jsx)(`p`,{className:`mt-1 text-xs text-muted-foreground line-clamp-3`,children:J.description})]}),(0,c.jsx)(`button`,{type:`button`,onClick:()=>A(null),className:`text-muted-foreground hover:text-foreground text-lg leading-none px-2`,"aria-label":`Close details`,"data-testid":`map-mobile-record-close`,children:`×`})]}),(0,c.jsxs)(`div`,{className:`mt-3 flex flex-wrap gap-2 text-xs`,children:[d&&(0,c.jsx)(`button`,{className:`px-3 py-1.5 rounded-md border bg-card hover:bg-accent`,onClick:()=>d(J.data),children:`Edit`}),f&&(0,c.jsx)(`button`,{className:`px-3 py-1.5 rounded-md border border-destructive/30 text-destructive hover:bg-destructive/10`,onClick:()=>f(J.data),children:`Delete`})]})]}),L&&(0,c.jsx)(`div`,{className:`absolute top-2 left-14 right-2 z-10 text-xs px-3 py-1.5 rounded-md bg-destructive/10 text-destructive border border-destructive/30`,children:L})]}),Z.isOverlay&&(0,c.jsx)(i.NavigationOverlay,{...Z,title:`Location Details`,children:e=>(0,c.jsx)(`div`,{className:`space-y-3`,children:Object.entries(e).map(([e,t])=>(0,c.jsxs)(`div`,{className:`flex flex-col`,children:[(0,c.jsx)(`span`,{className:`text-xs font-medium text-muted-foreground uppercase tracking-wide`,children:e.replace(/_/g,` `)}),(0,c.jsx)(`span`,{className:`text-sm`,children:String(t??`—`)})]},e))})})]})},w=({schema:e,...t})=>{let{dataSource:n}=(0,r.useSchemaContext)()||{};return(0,c.jsx)(C,{schema:e,dataSource:n,...t})};console.log(`Registering object-map...`),n.ComponentRegistry.register(`object-map`,w,{namespace:`plugin-map`,label:`Object Map`,category:`view`,inputs:[{name:`objectName`,type:`string`,label:`Object Name`,required:!0},{name:`map`,type:`object`,label:`Map Config`,description:`latitudeField, longitudeField, titleField`}]}),n.ComponentRegistry.register(`map`,w,{namespace:`view`,label:`Map View`,category:`view`,inputs:[{name:`objectName`,type:`string`,label:`Object Name`,required:!0},{name:`map`,type:`object`,label:`Map Config`,description:`latitudeField, longitudeField, titleField`}]}),e.ObjectMap=C,e.ObjectMapRenderer=w});
1
+ (function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require("react"),require("@object-ui/core"),require("@object-ui/react"),require("@object-ui/components"),require("zod"),require("react-map-gl/maplibre"),require("maplibre-gl/dist/maplibre-gl.css"),require("react/jsx-runtime")):typeof define==`function`&&define.amd?define([`exports`,`react`,`@object-ui/core`,`@object-ui/react`,`@object-ui/components`,`zod`,`react-map-gl/maplibre`,`maplibre-gl/dist/maplibre-gl.css`,`react/jsx-runtime`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.ObjectUIPluginMap={},e.React,e.ObjectUICore,e.ObjectUIReact,e.ObjectUIComponents,e.zod,e.react_map_gl_maplibre,e.maplibre_gl_dist_maplibre_gl_css,e.react_jsx_runtime))})(this,function(e,t,n,r,i,a,o,s,c){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var l=Object.create,u=Object.defineProperty,d=Object.getOwnPropertyDescriptor,f=Object.getOwnPropertyNames,p=Object.getPrototypeOf,m=Object.prototype.hasOwnProperty,h=(e,t,n,r)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var i=f(t),a=0,o=i.length,s;a<o;a++)s=i[a],!m.call(e,s)&&s!==n&&u(e,s,{get:(e=>t[e]).bind(null,s),enumerable:!(r=d(t,s))||r.enumerable});return e},g=(e,t,n)=>(n=e==null?{}:l(p(e)),h(t||!e||!e.__esModule?u(n,`default`,{value:e,enumerable:!0}):n,e));t=g(t,1),o=g(o,1);var _=a.z.object({latitudeField:a.z.string().optional(),longitudeField:a.z.string().optional(),locationField:a.z.string().optional(),titleField:a.z.string().optional(),descriptionField:a.z.string().optional(),zoom:a.z.number().optional(),center:a.z.tuple([a.z.number(),a.z.number()]).optional(),style:a.z.string().optional()}),ee=`https://demotiles.maplibre.org/style.json`;function te(e){return e.data?e.data:e.staticData?{provider:`value`,items:e.staticData}:e.objectName?{provider:`object`,object:e.objectName}:null}function v(e){if(e){if(typeof e==`string`){let t=e.split(` `),n=t[0],r=t[1]?.toLowerCase()===`desc`?`desc`:`asc`;return{[n]:r}}if(Array.isArray(e))return e.reduce((e,t)=>(t.field&&t.order&&(e[t.field]=t.order),e),{})}}function y(e){let t=e.style||e.mapStyle||e.filter?.map?.style||e.map?.style;if(e.locationField||e.latitudeField)return{locationField:e.locationField,latitudeField:e.latitudeField,longitudeField:e.longitudeField,titleField:e.titleField||`name`,descriptionField:e.descriptionField,zoom:e.zoom,center:e.center,style:t};let n=null;if(e.filter&&typeof e.filter==`object`&&`map`in e.filter?n=e.filter.map:e.map&&(n=e.map),n){let e=_.safeParse(n);return e.success||console.warn(`[ObjectMap] Invalid map configuration:`,e.error.format()),{...n,style:n.style||t}}return{latitudeField:`latitude`,longitudeField:`longitude`,locationField:`location`,titleField:`name`,descriptionField:`description`,zoom:10,center:[0,0],style:t}}function b(e,t){if(t.latitudeField&&t.longitudeField){let n=e[t.latitudeField],r=e[t.longitudeField];if(typeof n==`number`&&typeof r==`number`)return[n,r]}if(t.locationField){let n=e[t.locationField];if(typeof n==`object`&&n){let e=n.lat||n.latitude,t=n.lng||n.lon||n.longitude;if(typeof e==`number`&&typeof t==`number`)return[e,t]}if(typeof n==`string`){let e=n.split(`,`).map(e=>parseFloat(e.trim()));if(e.length===2&&!isNaN(e[0])&&!isNaN(e[1]))return[e[0],e[1]]}if(Array.isArray(n)&&n.length===2){let e=parseFloat(n[0]),t=parseFloat(n[1]);if(!isNaN(e)&&!isNaN(t))return[e,t]}}return null}function x(e,t,n=50){if(e.length<=1||t>=15)return e.map(e=>({id:e.id,coordinates:e.coordinates,markers:[e],isCluster:!1}));let r=n/2**t,i=new Map;e.forEach(e=>{let t=`${Math.floor(e.coordinates[0]/r)}:${Math.floor(e.coordinates[1]/r)}`;i.has(t)||i.set(t,[]),i.get(t).push(e)});let a=[];return i.forEach((e,t)=>{if(e.length===1)a.push({id:e[0].id,coordinates:e[0].coordinates,markers:e,isCluster:!1});else{let n=e.reduce((e,t)=>e+t.coordinates[0],0)/e.length,r=e.reduce((e,t)=>e+t.coordinates[1],0)/e.length;a.push({id:`cluster-${t}`,coordinates:[n,r],markers:e,isCluster:!0})}}),a}var S=({schema:e,dataSource:a,className:s,onMarkerClick:l,onRowClick:u,onEdit:d,onDelete:f,enableClustering:p,clusterRadius:m=50,...h})=>{let[g,_]=(0,t.useState)([]),[S,C]=(0,t.useState)(!0),[w,T]=(0,t.useState)(null),[E,D]=(0,t.useState)(null),[O,k]=(0,t.useState)(null),[A,j]=(0,t.useState)(``),M=(0,i.useIsMobile)(),N=(0,t.useRef)(null),[P,F]=(0,t.useState)(null),[I,L]=(0,t.useState)(null),[R,z]=(0,t.useState)(!1),[B,V]=(0,t.useState)(null),ne=(0,t.useCallback)(e=>{V(e?.error?.message||`Failed to load the map style/tiles.`)},[]),H=(0,t.useCallback)(()=>{if(typeof navigator>`u`||!navigator.geolocation){L(`Geolocation is not available in this browser.`);return}z(!0),L(null),navigator.geolocation.getCurrentPosition(e=>{let{longitude:t,latitude:n}=e.coords;F({lng:t,lat:n}),z(!1);try{N.current?.flyTo({center:[t,n],zoom:12,duration:800})}catch{}},e=>{z(!1),L(e.message||`Unable to retrieve location.`)},{enableHighAccuracy:!1,timeout:8e3,maximumAge:6e4})},[]),U=te(e),W=(0,t.useMemo)(()=>U,[JSON.stringify(U)]),G=y(e),K=W?.provider===`value`;(0,t.useEffect)(()=>{(async()=>{try{if(C(!0),h.data){let e=h.data;if(Array.isArray(e)){_(e),C(!1);return}}if(e.data){let t=e.data;if(Array.isArray(t)){_(t),C(!1);return}}if(K&&W?.provider===`value`){_(W.items),C(!1);return}if(!a||typeof a.find!=`function`)throw Error(`DataSource required for object/api providers`);if(W?.provider===`object`){let t=W.object,r=(0,n.buildExpandFields)(E?.fields);_((0,n.extractRecords)(await a.find(t,{$filter:e.filter,$orderby:v(e.sort),...r.length>0?{$expand:r}:{}})))}else W?.provider===`api`&&(console.warn(`API provider not yet implemented for ObjectMap`),_([]));C(!1)}catch(e){T(e),C(!1)}})()},[W,a,K,e.filter,e.sort,E]),(0,t.useEffect)(()=>{!K&&a&&(async()=>{try{if(!a)return;let t=W?.provider===`object`?W.object:e.objectName;if(!t)return;D(await a.getObjectSchema(t))}catch(e){console.error(`Failed to fetch object schema:`,e)}})()},[e.objectName,a,K,W]);let{markers:q,invalidCount:J}=(0,t.useMemo)(()=>{let e=0;return{markers:g.map((t,n)=>{let r=b(t,G);if(!r)return e++,null;let i=G.titleField?t[G.titleField]:`Marker`,a=G.descriptionField?t[G.descriptionField]:void 0,[o,s]=r;return!isFinite(o)||!isFinite(s)||o<-90||o>90||s<-180||s>180?(e++,null):{id:t.id||t._id||`marker-${n}`,title:i,description:a,coordinates:[s,o],data:t}}).filter(e=>e!==null),invalidCount:e}},[g,G]),Y=(0,t.useMemo)(()=>q.find(e=>e.id===O),[q,O]),[X,Z]=(0,t.useState)(G.zoom||3),Q=(0,r.useNavigationOverlay)({navigation:e.navigation,objectName:e.objectName,onRowClick:u}),$=(0,t.useMemo)(()=>{if(!A.trim())return q;let e=A.toLowerCase();return q.filter(t=>t.title?.toLowerCase().includes(e)||t.description?.toLowerCase().includes(e))},[q,A]),re=(0,t.useMemo)(()=>p??(e.enableClustering||$.length>100)?x($,X,m):$.map(e=>({id:e.id,coordinates:e.coordinates,markers:[e],isCluster:!1})),[$,X,p,m,e]),ie=(0,t.useMemo)(()=>{if(!$.length)return{longitude:G.center?.[1]||0,latitude:G.center?.[0]||0,zoom:G.zoom||2};let e=$.map(e=>e.coordinates[0]),t=$.map(e=>e.coordinates[1]),n=Math.min(...e),r=Math.max(...e),i=Math.min(...t),a=Math.max(...t);return{longitude:(n+r)/2,latitude:(i+a)/2,zoom:G.zoom||3}},[$,G]);return S?(0,c.jsx)(`div`,{className:(0,i.cn)(`min-w-0 overflow-hidden`,s),children:(0,c.jsx)(`div`,{className:`flex items-center justify-center h-96 bg-muted rounded-lg border`,children:(0,c.jsx)(`div`,{className:`text-muted-foreground`,children:`Loading map...`})})}):w?(0,c.jsx)(`div`,{className:(0,i.cn)(`min-w-0 overflow-hidden`,s),children:(0,c.jsx)(`div`,{className:`flex items-center justify-center h-96 bg-muted rounded-lg border`,children:(0,c.jsxs)(`div`,{className:`text-destructive`,children:[`Error: `,w.message]})})}):(0,c.jsxs)(`div`,{className:(0,i.cn)(`min-w-0 overflow-hidden`,s),children:[J>0&&(0,c.jsx)(`div`,{className:`mb-2 p-2 text-sm text-yellow-800 bg-yellow-50 border border-yellow-200 rounded`,children:`${J} record${J===1?``:`s`} with missing or invalid coordinates excluded from the map.`}),q.length>0&&(0,c.jsx)(`div`,{className:`mb-2`,children:(0,c.jsx)(`input`,{type:`text`,value:A,onChange:e=>j(e.target.value),placeholder:`Search locations…`,className:`w-full px-3 py-2 text-sm border rounded-md bg-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring`})}),(0,c.jsxs)(`div`,{className:`relative border rounded-lg overflow-hidden bg-muted h-[300px] sm:h-[400px] md:h-[500px] lg:h-[600px] w-full`,children:[(0,c.jsxs)(o.default,{ref:e=>{N.current=e},initialViewState:ie,style:{width:`100%`,height:`100%`},mapStyle:G.style||ee,touchZoomRotate:!0,dragRotate:!0,touchPitch:!0,onZoom:e=>Z(Math.round(e.viewState.zoom)),onError:ne,children:[B&&(0,c.jsxs)(`div`,{role:`alert`,className:`absolute inset-x-0 top-0 z-20 p-2 text-sm text-center text-amber-900 bg-amber-50 border-b border-amber-200`,children:[`Map failed to load (`,B,`). Markers below are still listed in the search box;`,` `,G.style?`check the configured map style URL.`:`configure a custom map style for production use.`]}),(0,c.jsx)(o.NavigationControl,{position:`top-right`,showCompass:!0,showZoom:!0}),(0,c.jsx)(`button`,{type:`button`,onClick:H,disabled:R,className:`absolute top-2 left-2 z-10 inline-flex items-center justify-center size-9 rounded-md bg-background/95 border shadow-sm hover:bg-background disabled:opacity-50`,"aria-label":`Show my location`,"data-testid":`map-geolocate`,children:(0,c.jsx)(`span`,{"aria-hidden":`true`,children:R?`⏳`:`🧭`})}),P&&(0,c.jsx)(o.Marker,{longitude:P.lng,latitude:P.lat,anchor:`center`,children:(0,c.jsx)(`div`,{className:`size-3 rounded-full bg-blue-500 ring-4 ring-blue-500/30 shadow`,"aria-label":`Your location`,"data-testid":`map-user-location`})}),re.map(e=>e.isCluster?(0,c.jsx)(o.Marker,{longitude:e.coordinates[0],latitude:e.coordinates[1],anchor:`center`,onClick:t=>{t.originalEvent.stopPropagation();try{let t=Math.min(20,Math.max(X+2,8));N.current?.flyTo({center:[e.coordinates[0],e.coordinates[1]],zoom:t,duration:600})}catch{}},children:(0,c.jsx)(`div`,{className:`flex items-center justify-center rounded-full bg-primary text-primary-foreground font-bold text-xs cursor-pointer hover:scale-110 transition-transform shadow-md`,style:{width:Math.min(48,24+e.markers.length*2),height:Math.min(48,24+e.markers.length*2)},title:`${e.markers.length} markers`,"data-testid":`map-cluster`,children:e.markers.length})},e.id):(0,c.jsx)(o.Marker,{longitude:e.coordinates[0],latitude:e.coordinates[1],anchor:`bottom`,onClick:t=>{t.originalEvent.stopPropagation();let n=e.markers[0];k(n.id),Q.handleClick(n.data),l?.(n.data)},children:(0,c.jsx)(`div`,{className:`text-2xl cursor-pointer hover:scale-110 transition-transform`,children:`📍`})},e.id)),Y&&!M&&(0,c.jsx)(o.Popup,{longitude:Y.coordinates[0],latitude:Y.coordinates[1],anchor:`top`,onClose:()=>k(null),closeOnClick:!1,children:(0,c.jsxs)(`div`,{className:`p-2 min-w-[150px] sm:min-w-[200px]`,children:[(0,c.jsx)(`h3`,{className:`font-bold text-sm mb-1`,children:Y.title}),Y.description&&(0,c.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:Y.description}),(0,c.jsxs)(`div`,{className:`mt-2 text-xs flex gap-2`,children:[d&&(0,c.jsx)(`button`,{className:`text-blue-500 hover:underline`,onClick:()=>d(Y.data),children:`Edit`}),f&&(0,c.jsx)(`button`,{className:`text-red-500 hover:underline`,onClick:()=>f(Y.data),children:`Delete`})]})]})})]}),Y&&M&&(0,c.jsxs)(`div`,{className:`absolute inset-x-0 bottom-0 z-30 bg-background border-t shadow-lg rounded-t-2xl p-4 pb-[max(env(safe-area-inset-bottom),1rem)]`,role:`dialog`,"aria-label":`Location details`,"data-testid":`map-mobile-record-sheet`,children:[(0,c.jsx)(`div`,{className:`mx-auto mb-2 h-1 w-10 rounded-full bg-muted`,"aria-hidden":`true`}),(0,c.jsxs)(`div`,{className:`flex items-start justify-between gap-3`,children:[(0,c.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,c.jsx)(`h3`,{className:`text-sm font-semibold truncate`,children:Y.title}),Y.description&&(0,c.jsx)(`p`,{className:`mt-1 text-xs text-muted-foreground line-clamp-3`,children:Y.description})]}),(0,c.jsx)(`button`,{type:`button`,onClick:()=>k(null),className:`text-muted-foreground hover:text-foreground text-lg leading-none px-2`,"aria-label":`Close details`,"data-testid":`map-mobile-record-close`,children:`×`})]}),(0,c.jsxs)(`div`,{className:`mt-3 flex flex-wrap gap-2 text-xs`,children:[d&&(0,c.jsx)(`button`,{className:`px-3 py-1.5 rounded-md border bg-card hover:bg-accent`,onClick:()=>d(Y.data),children:`Edit`}),f&&(0,c.jsx)(`button`,{className:`px-3 py-1.5 rounded-md border border-destructive/30 text-destructive hover:bg-destructive/10`,onClick:()=>f(Y.data),children:`Delete`})]})]}),I&&(0,c.jsx)(`div`,{className:`absolute top-2 left-14 right-2 z-10 text-xs px-3 py-1.5 rounded-md bg-destructive/10 text-destructive border border-destructive/30`,children:I})]}),Q.isOverlay&&(0,c.jsx)(i.NavigationOverlay,{...Q,title:`Location Details`,children:e=>(0,c.jsx)(`div`,{className:`space-y-3`,children:Object.entries(e).map(([e,t])=>(0,c.jsxs)(`div`,{className:`flex flex-col`,children:[(0,c.jsx)(`span`,{className:`text-xs font-medium text-muted-foreground uppercase tracking-wide`,children:e.replace(/_/g,` `)}),(0,c.jsx)(`span`,{className:`text-sm`,children:String(t??`—`)})]},e))})})]})},C=({schema:e,...t})=>{let{dataSource:n}=(0,r.useSchemaContext)()||{};return(0,c.jsx)(S,{schema:e,dataSource:n,...t})};console.log(`Registering object-map...`),n.ComponentRegistry.register(`object-map`,C,{namespace:`plugin-map`,label:`Object Map`,category:`view`,inputs:[{name:`objectName`,type:`string`,label:`Object Name`,required:!0},{name:`map`,type:`object`,label:`Map Config`,description:`latitudeField, longitudeField, titleField`}]}),n.ComponentRegistry.register(`map`,C,{namespace:`view`,label:`Map View`,category:`view`,inputs:[{name:`objectName`,type:`string`,label:`Object Name`,required:!0},{name:`map`,type:`object`,label:`Map Config`,description:`latitudeField, longitudeField, titleField`}]}),e.ObjectMap=S,e.ObjectMapRenderer=C});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@object-ui/plugin-map",
3
- "version": "11.3.0",
3
+ "version": "11.5.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Map visualization plugin for Object UI",
@@ -24,15 +24,15 @@
24
24
  }
25
25
  },
26
26
  "dependencies": {
27
- "@objectstack/spec": "^11.2.0",
27
+ "@objectstack/spec": "^11.7.0",
28
28
  "lucide-react": "^1.22.0",
29
29
  "maplibre-gl": "^5.24.0",
30
30
  "react-map-gl": "^8.1.1",
31
31
  "zod": "^4.4.3",
32
- "@object-ui/components": "11.3.0",
33
- "@object-ui/core": "11.3.0",
34
- "@object-ui/react": "11.3.0",
35
- "@object-ui/types": "11.3.0"
32
+ "@object-ui/components": "11.5.0",
33
+ "@object-ui/core": "11.5.0",
34
+ "@object-ui/react": "11.5.0",
35
+ "@object-ui/types": "11.5.0"
36
36
  },
37
37
  "peerDependencies": {
38
38
  "react": "^18.0.0 || ^19.0.0",