@object-ui/plugin-map 11.4.0 → 13.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,60 @@
1
1
  # @object-ui/plugin-map
2
2
 
3
+ ## 13.1.0
4
+
5
+ ### Patch Changes
6
+
7
+ - @object-ui/types@13.1.0
8
+ - @object-ui/core@13.1.0
9
+ - @object-ui/react@13.1.0
10
+ - @object-ui/components@13.1.0
11
+
12
+ ## 13.0.0
13
+
14
+ ### Patch Changes
15
+
16
+ - Updated dependencies [ac04b76]
17
+ - Updated dependencies [619097e]
18
+ - @object-ui/components@13.0.0
19
+ - @object-ui/types@13.0.0
20
+ - @object-ui/react@13.0.0
21
+ - @object-ui/core@13.0.0
22
+
23
+ ## 12.1.0
24
+
25
+ ### Patch Changes
26
+
27
+ - Updated dependencies [6cbccf3]
28
+ - Updated dependencies [c31874d]
29
+ - @object-ui/components@12.1.0
30
+ - @object-ui/types@12.1.0
31
+ - @object-ui/react@12.1.0
32
+ - @object-ui/core@12.1.0
33
+
34
+ ## 12.0.0
35
+
36
+ ### Patch Changes
37
+
38
+ - Updated dependencies [226fde9]
39
+ - Updated dependencies [e4de456]
40
+ - @object-ui/types@12.0.0
41
+ - @object-ui/core@12.0.0
42
+ - @object-ui/components@12.0.0
43
+ - @object-ui/react@12.0.0
44
+
45
+ ## 11.5.0
46
+
47
+ ### Patch Changes
48
+
49
+ - Updated dependencies [6fffd3d]
50
+ - Updated dependencies [9255686]
51
+ - Updated dependencies [fae75e2]
52
+ - Updated dependencies [1072701]
53
+ - @object-ui/react@11.5.0
54
+ - @object-ui/components@11.5.0
55
+ - @object-ui/types@11.5.0
56
+ - @object-ui/core@11.5.0
57
+
3
58
  ## 11.4.0
4
59
 
5
60
  ### 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), n = s(await c.find(e, {
167
175
  $filter: a.filter,
168
- $orderby: _(a.sort),
176
+ $orderby: oe(a.sort),
169
177
  ...t.length > 0 ? { $expand: t } : {}
170
- })));
171
- } else G?.provider === "api" && (console.warn("API provider not yet implemented for ObjectMap"), D([]));
172
- O(!1);
178
+ }));
179
+ E(n);
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,15 @@ 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
+ let t = await c.getObjectSchema(e);
200
+ j(t);
191
201
  } catch (e) {
192
202
  console.error("Failed to fetch object schema:", e);
193
203
  }
@@ -201,8 +211,8 @@ var b = ({ schema: a, dataSource: c, className: d, onMarkerClick: g, onRowClick:
201
211
  let { markers: J, invalidCount: Y } = n(() => {
202
212
  let e = 0;
203
213
  return {
204
- markers: E.map((t, n) => {
205
- let r = y(t, K);
214
+ markers: T.map((t, n) => {
215
+ let r = v(t, K);
206
216
  if (!r) return e++, null;
207
217
  let i = K.titleField ? t[K.titleField] : "Marker", a = K.descriptionField ? t[K.descriptionField] : void 0, [o, s] = r;
208
218
  return !isFinite(o) || !isFinite(s) || o < -90 || o > 90 || s < -180 || s > 180 ? (e++, null) : {
@@ -215,15 +225,15 @@ var b = ({ schema: a, dataSource: c, className: d, onMarkerClick: g, onRowClick:
215
225
  }).filter((e) => e !== null),
216
226
  invalidCount: e
217
227
  };
218
- }, [E, K]), X = n(() => J.find((e) => e.id === N), [J, N]), [Z, le] = i(K.zoom || 3), Q = ee({
228
+ }, [T, K]), X = n(() => J.find((e) => e.id === M), [J, M]), [Z, pe] = i(K.zoom || 3), Q = ee({
219
229
  navigation: a.navigation,
220
230
  objectName: a.objectName,
221
- onRowClick: b
231
+ onRowClick: y
222
232
  }), $ = n(() => {
223
- if (!F.trim()) return J;
224
- let e = F.toLowerCase();
233
+ if (!P.trim()) return J;
234
+ let e = P.toLowerCase();
225
235
  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) => ({
236
+ }, [J, P]), me = n(() => S ?? (a.enableClustering || $.length > 100) ? se($, Z, C) : $.map((e) => ({
227
237
  id: e.id,
228
238
  coordinates: e.coordinates,
229
239
  markers: [e],
@@ -231,10 +241,10 @@ var b = ({ schema: a, dataSource: c, className: d, onMarkerClick: g, onRowClick:
231
241
  })), [
232
242
  $,
233
243
  Z,
244
+ S,
234
245
  C,
235
- w,
236
246
  a
237
- ]), de = n(() => {
247
+ ]), he = n(() => {
238
248
  if (!$.length) return {
239
249
  longitude: K.center?.[1] || 0,
240
250
  latitude: K.center?.[0] || 0,
@@ -247,87 +257,99 @@ var b = ({ schema: a, dataSource: c, className: d, onMarkerClick: g, onRowClick:
247
257
  zoom: K.zoom || 3
248
258
  };
249
259
  }, [$, K]);
250
- return oe ? /* @__PURE__ */ m("div", {
251
- className: l("min-w-0 overflow-hidden", d),
252
- children: /* @__PURE__ */ m("div", {
260
+ return ce ? /* @__PURE__ */ p("div", {
261
+ className: l("min-w-0 overflow-hidden", u),
262
+ children: /* @__PURE__ */ p("div", {
253
263
  className: "flex items-center justify-center h-96 bg-muted rounded-lg border",
254
- children: /* @__PURE__ */ m("div", {
264
+ children: /* @__PURE__ */ p("div", {
255
265
  className: "text-muted-foreground",
256
266
  children: "Loading map..."
257
267
  })
258
268
  })
259
- }) : k ? /* @__PURE__ */ m("div", {
260
- className: l("min-w-0 overflow-hidden", d),
261
- children: /* @__PURE__ */ m("div", {
269
+ }) : O ? /* @__PURE__ */ p("div", {
270
+ className: l("min-w-0 overflow-hidden", u),
271
+ children: /* @__PURE__ */ p("div", {
262
272
  className: "flex items-center justify-center h-96 bg-muted rounded-lg border",
263
- children: /* @__PURE__ */ h("div", {
273
+ children: /* @__PURE__ */ m("div", {
264
274
  className: "text-destructive",
265
- children: ["Error: ", k.message]
275
+ children: ["Error: ", O.message]
266
276
  })
267
277
  })
268
- }) : /* @__PURE__ */ h("div", {
269
- className: l("min-w-0 overflow-hidden", d),
278
+ }) : /* @__PURE__ */ m("div", {
279
+ className: l("min-w-0 overflow-hidden", u),
270
280
  children: [
271
- Y > 0 && /* @__PURE__ */ m("div", {
281
+ Y > 0 && /* @__PURE__ */ p("div", {
272
282
  className: "mb-2 p-2 text-sm text-yellow-800 bg-yellow-50 border border-yellow-200 rounded",
273
283
  children: `${Y} record${Y === 1 ? "" : "s"} with missing or invalid coordinates excluded from the map.`
274
284
  }),
275
- J.length > 0 && /* @__PURE__ */ m("div", {
285
+ J.length > 0 && /* @__PURE__ */ p("div", {
276
286
  className: "mb-2",
277
- children: /* @__PURE__ */ m("input", {
287
+ children: /* @__PURE__ */ p("input", {
278
288
  type: "text",
279
- value: F,
280
- onChange: (e) => se(e.target.value),
289
+ value: P,
290
+ onChange: (e) => le(e.target.value),
281
291
  placeholder: "Search locations…",
282
292
  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
293
  })
284
294
  }),
285
- /* @__PURE__ */ h("div", {
295
+ /* @__PURE__ */ m("div", {
286
296
  className: "relative border rounded-lg overflow-hidden bg-muted h-[300px] sm:h-[400px] md:h-[500px] lg:h-[600px] w-full",
287
297
  children: [
288
- /* @__PURE__ */ h(ne, {
298
+ /* @__PURE__ */ m(d, {
289
299
  ref: (e) => {
290
- L.current = e;
300
+ I.current = e;
291
301
  },
292
- initialViewState: de,
302
+ initialViewState: he,
293
303
  style: {
294
304
  width: "100%",
295
305
  height: "100%"
296
306
  },
297
- mapStyle: "https://demotiles.maplibre.org/style.json",
307
+ mapStyle: K.style || ae,
298
308
  touchZoomRotate: !0,
299
309
  dragRotate: !0,
300
310
  touchPitch: !0,
301
- onZoom: (e) => le(Math.round(e.viewState.zoom)),
311
+ onZoom: (e) => pe(Math.round(e.viewState.zoom)),
312
+ onError: de,
302
313
  children: [
303
- /* @__PURE__ */ m(re, {
314
+ U && /* @__PURE__ */ m("div", {
315
+ role: "alert",
316
+ 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",
317
+ children: [
318
+ "Map failed to load (",
319
+ U,
320
+ "). Markers below are still listed in the search box;",
321
+ " ",
322
+ K.style ? "check the configured map style URL." : "configure a custom map style for production use."
323
+ ]
324
+ }),
325
+ /* @__PURE__ */ p(re, {
304
326
  position: "top-right",
305
327
  showCompass: !0,
306
328
  showZoom: !0
307
329
  }),
308
- /* @__PURE__ */ m("button", {
330
+ /* @__PURE__ */ p("button", {
309
331
  type: "button",
310
- onClick: U,
332
+ onClick: fe,
311
333
  disabled: V,
312
334
  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
335
  "aria-label": "Show my location",
314
336
  "data-testid": "map-geolocate",
315
- children: /* @__PURE__ */ m("span", {
337
+ children: /* @__PURE__ */ p("span", {
316
338
  "aria-hidden": "true",
317
339
  children: V ? "⏳" : "🧭"
318
340
  })
319
341
  }),
320
- R && /* @__PURE__ */ m(f, {
321
- longitude: R.lng,
322
- latitude: R.lat,
342
+ L && /* @__PURE__ */ p(f, {
343
+ longitude: L.lng,
344
+ latitude: L.lat,
323
345
  anchor: "center",
324
- children: /* @__PURE__ */ m("div", {
346
+ children: /* @__PURE__ */ p("div", {
325
347
  className: "size-3 rounded-full bg-blue-500 ring-4 ring-blue-500/30 shadow",
326
348
  "aria-label": "Your location",
327
349
  "data-testid": "map-user-location"
328
350
  })
329
351
  }),
330
- ue.map((e) => e.isCluster ? /* @__PURE__ */ m(f, {
352
+ me.map((e) => e.isCluster ? /* @__PURE__ */ p(f, {
331
353
  longitude: e.coordinates[0],
332
354
  latitude: e.coordinates[1],
333
355
  anchor: "center",
@@ -335,14 +357,14 @@ var b = ({ schema: a, dataSource: c, className: d, onMarkerClick: g, onRowClick:
335
357
  t.originalEvent.stopPropagation();
336
358
  try {
337
359
  let t = Math.min(20, Math.max(Z + 2, 8));
338
- L.current?.flyTo({
360
+ I.current?.flyTo({
339
361
  center: [e.coordinates[0], e.coordinates[1]],
340
362
  zoom: t,
341
363
  duration: 600
342
364
  });
343
365
  } catch {}
344
366
  },
345
- children: /* @__PURE__ */ m("div", {
367
+ children: /* @__PURE__ */ p("div", {
346
368
  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
369
  style: {
348
370
  width: Math.min(48, 24 + e.markers.length * 2),
@@ -352,46 +374,46 @@ var b = ({ schema: a, dataSource: c, className: d, onMarkerClick: g, onRowClick:
352
374
  "data-testid": "map-cluster",
353
375
  children: e.markers.length
354
376
  })
355
- }, e.id) : /* @__PURE__ */ m(f, {
377
+ }, e.id) : /* @__PURE__ */ p(f, {
356
378
  longitude: e.coordinates[0],
357
379
  latitude: e.coordinates[1],
358
380
  anchor: "bottom",
359
381
  onClick: (t) => {
360
382
  t.originalEvent.stopPropagation();
361
383
  let n = e.markers[0];
362
- P(n.id), Q.handleClick(n.data), g?.(n.data);
384
+ N(n.id), Q.handleClick(n.data), h?.(n.data);
363
385
  },
364
- children: /* @__PURE__ */ m("div", {
386
+ children: /* @__PURE__ */ p("div", {
365
387
  className: "text-2xl cursor-pointer hover:scale-110 transition-transform",
366
388
  children: "📍"
367
389
  })
368
390
  }, e.id)),
369
- X && !I && /* @__PURE__ */ m(p, {
391
+ X && !F && /* @__PURE__ */ p(ie, {
370
392
  longitude: X.coordinates[0],
371
393
  latitude: X.coordinates[1],
372
394
  anchor: "top",
373
- onClose: () => P(null),
395
+ onClose: () => N(null),
374
396
  closeOnClick: !1,
375
- children: /* @__PURE__ */ h("div", {
397
+ children: /* @__PURE__ */ m("div", {
376
398
  className: "p-2 min-w-[150px] sm:min-w-[200px]",
377
399
  children: [
378
- /* @__PURE__ */ m("h3", {
400
+ /* @__PURE__ */ p("h3", {
379
401
  className: "font-bold text-sm mb-1",
380
402
  children: X.title
381
403
  }),
382
- X.description && /* @__PURE__ */ m("p", {
404
+ X.description && /* @__PURE__ */ p("p", {
383
405
  className: "text-xs text-muted-foreground",
384
406
  children: X.description
385
407
  }),
386
- /* @__PURE__ */ h("div", {
408
+ /* @__PURE__ */ m("div", {
387
409
  className: "mt-2 text-xs flex gap-2",
388
- children: [x && /* @__PURE__ */ m("button", {
410
+ children: [b && /* @__PURE__ */ p("button", {
389
411
  className: "text-blue-500 hover:underline",
390
- onClick: () => x(X.data),
412
+ onClick: () => b(X.data),
391
413
  children: "Edit"
392
- }), S && /* @__PURE__ */ m("button", {
414
+ }), x && /* @__PURE__ */ p("button", {
393
415
  className: "text-red-500 hover:underline",
394
- onClick: () => S(X.data),
416
+ onClick: () => x(X.data),
395
417
  children: "Delete"
396
418
  })]
397
419
  })
@@ -400,67 +422,67 @@ var b = ({ schema: a, dataSource: c, className: d, onMarkerClick: g, onRowClick:
400
422
  })
401
423
  ]
402
424
  }),
403
- X && I && /* @__PURE__ */ h("div", {
425
+ X && F && /* @__PURE__ */ m("div", {
404
426
  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
427
  role: "dialog",
406
428
  "aria-label": "Location details",
407
429
  "data-testid": "map-mobile-record-sheet",
408
430
  children: [
409
- /* @__PURE__ */ m("div", {
431
+ /* @__PURE__ */ p("div", {
410
432
  className: "mx-auto mb-2 h-1 w-10 rounded-full bg-muted",
411
433
  "aria-hidden": "true"
412
434
  }),
413
- /* @__PURE__ */ h("div", {
435
+ /* @__PURE__ */ m("div", {
414
436
  className: "flex items-start justify-between gap-3",
415
- children: [/* @__PURE__ */ h("div", {
437
+ children: [/* @__PURE__ */ m("div", {
416
438
  className: "min-w-0 flex-1",
417
- children: [/* @__PURE__ */ m("h3", {
439
+ children: [/* @__PURE__ */ p("h3", {
418
440
  className: "text-sm font-semibold truncate",
419
441
  children: X.title
420
- }), X.description && /* @__PURE__ */ m("p", {
442
+ }), X.description && /* @__PURE__ */ p("p", {
421
443
  className: "mt-1 text-xs text-muted-foreground line-clamp-3",
422
444
  children: X.description
423
445
  })]
424
- }), /* @__PURE__ */ m("button", {
446
+ }), /* @__PURE__ */ p("button", {
425
447
  type: "button",
426
- onClick: () => P(null),
448
+ onClick: () => N(null),
427
449
  className: "text-muted-foreground hover:text-foreground text-lg leading-none px-2",
428
450
  "aria-label": "Close details",
429
451
  "data-testid": "map-mobile-record-close",
430
452
  children: "×"
431
453
  })]
432
454
  }),
433
- /* @__PURE__ */ h("div", {
455
+ /* @__PURE__ */ m("div", {
434
456
  className: "mt-3 flex flex-wrap gap-2 text-xs",
435
- children: [x && /* @__PURE__ */ m("button", {
457
+ children: [b && /* @__PURE__ */ p("button", {
436
458
  className: "px-3 py-1.5 rounded-md border bg-card hover:bg-accent",
437
- onClick: () => x(X.data),
459
+ onClick: () => b(X.data),
438
460
  children: "Edit"
439
- }), S && /* @__PURE__ */ m("button", {
461
+ }), x && /* @__PURE__ */ p("button", {
440
462
  className: "px-3 py-1.5 rounded-md border border-destructive/30 text-destructive hover:bg-destructive/10",
441
- onClick: () => S(X.data),
463
+ onClick: () => x(X.data),
442
464
  children: "Delete"
443
465
  })]
444
466
  })
445
467
  ]
446
468
  }),
447
- z && /* @__PURE__ */ m("div", {
469
+ z && /* @__PURE__ */ p("div", {
448
470
  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
471
  children: z
450
472
  })
451
473
  ]
452
474
  }),
453
- Q.isOverlay && /* @__PURE__ */ m(te, {
475
+ Q.isOverlay && /* @__PURE__ */ p(te, {
454
476
  ...Q,
455
477
  title: "Location Details",
456
- children: (e) => /* @__PURE__ */ m("div", {
478
+ children: (e) => /* @__PURE__ */ p("div", {
457
479
  className: "space-y-3",
458
- children: Object.entries(e).map(([e, t]) => /* @__PURE__ */ h("div", {
480
+ children: Object.entries(e).map(([e, t]) => /* @__PURE__ */ m("div", {
459
481
  className: "flex flex-col",
460
- children: [/* @__PURE__ */ m("span", {
482
+ children: [/* @__PURE__ */ p("span", {
461
483
  className: "text-xs font-medium text-muted-foreground uppercase tracking-wide",
462
484
  children: e.replace(/_/g, " ")
463
- }), /* @__PURE__ */ m("span", {
485
+ }), /* @__PURE__ */ p("span", {
464
486
  className: "text-sm",
465
487
  children: String(t ?? "—")
466
488
  })]
@@ -469,15 +491,15 @@ var b = ({ schema: a, dataSource: c, className: d, onMarkerClick: g, onRowClick:
469
491
  })
470
492
  ]
471
493
  });
472
- }, x = ({ schema: e, ...t }) => {
494
+ }, b = ({ schema: e, ...t }) => {
473
495
  let { dataSource: n } = c() || {};
474
- return /* @__PURE__ */ m(b, {
496
+ return /* @__PURE__ */ p(y, {
475
497
  schema: e,
476
498
  dataSource: n,
477
499
  ...t
478
500
  });
479
501
  };
480
- console.log("Registering object-map..."), a.register("object-map", x, {
502
+ console.log("Registering object-map..."), a.register("object-map", b, {
481
503
  namespace: "plugin-map",
482
504
  label: "Object Map",
483
505
  category: "view",
@@ -492,7 +514,7 @@ console.log("Registering object-map..."), a.register("object-map", x, {
492
514
  label: "Map Config",
493
515
  description: "latitudeField, longitudeField, titleField"
494
516
  }]
495
- }), a.register("map", x, {
517
+ }), a.register("map", b, {
496
518
  namespace: "view",
497
519
  label: "Map View",
498
520
  category: "view",
@@ -509,4 +531,4 @@ console.log("Registering object-map..."), a.register("object-map", x, {
509
531
  }]
510
532
  });
511
533
  //#endregion
512
- export { b as ObjectMap, x as ObjectMapRenderer };
534
+ 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),i=(0,n.extractRecords)(await a.find(t,{$filter:e.filter,$orderby:v(e.sort),...r.length>0?{$expand:r}:{}}));_(i)}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;let n=await a.getObjectSchema(t);D(n)}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.4.0",
3
+ "version": "13.1.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.7.0",
27
+ "@objectstack/spec": "^13.0.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.4.0",
33
- "@object-ui/core": "11.4.0",
34
- "@object-ui/react": "11.4.0",
35
- "@object-ui/types": "11.4.0"
32
+ "@object-ui/components": "13.1.0",
33
+ "@object-ui/core": "13.1.0",
34
+ "@object-ui/react": "13.1.0",
35
+ "@object-ui/types": "13.1.0"
36
36
  },
37
37
  "peerDependencies": {
38
38
  "react": "^18.0.0 || ^19.0.0",
@@ -43,7 +43,7 @@
43
43
  "@types/react-dom": "19.2.3",
44
44
  "@vitejs/plugin-react": "^6.0.3",
45
45
  "typescript": "^6.0.3",
46
- "vite": "^8.1.0",
46
+ "vite": "^8.1.3",
47
47
  "vite-plugin-dts": "^5.0.3"
48
48
  },
49
49
  "keywords": [