@object-ui/plugin-map 17.2.0 → 17.3.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 +40 -0
- package/dist/index.js +3 -3
- package/dist/index.umd.cjs +1 -1
- package/package.json +13 -13
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,45 @@
|
|
|
1
1
|
# @object-ui/plugin-map
|
|
2
2
|
|
|
3
|
+
## 17.3.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [18cd432]
|
|
8
|
+
- Updated dependencies [532cf8b]
|
|
9
|
+
- Updated dependencies [680080a]
|
|
10
|
+
- Updated dependencies [a7651e6]
|
|
11
|
+
- Updated dependencies [d915c47]
|
|
12
|
+
- Updated dependencies [b71fc92]
|
|
13
|
+
- Updated dependencies [34595eb]
|
|
14
|
+
- Updated dependencies [3889ffb]
|
|
15
|
+
- Updated dependencies [5781fb1]
|
|
16
|
+
- Updated dependencies [9e9e9a9]
|
|
17
|
+
- Updated dependencies [56409c2]
|
|
18
|
+
- Updated dependencies [042e09d]
|
|
19
|
+
- Updated dependencies [9cbcbf4]
|
|
20
|
+
- Updated dependencies [85c4c9c]
|
|
21
|
+
- Updated dependencies [fd54c3e]
|
|
22
|
+
- Updated dependencies [4eeb932]
|
|
23
|
+
- Updated dependencies [23018cc]
|
|
24
|
+
- Updated dependencies [53811d1]
|
|
25
|
+
- Updated dependencies [d915c47]
|
|
26
|
+
- Updated dependencies [f44d872]
|
|
27
|
+
- Updated dependencies [509104a]
|
|
28
|
+
- Updated dependencies [825bbe3]
|
|
29
|
+
- Updated dependencies [5dd0127]
|
|
30
|
+
- Updated dependencies [06632e9]
|
|
31
|
+
- Updated dependencies [a4cff5b]
|
|
32
|
+
- Updated dependencies [175bd79]
|
|
33
|
+
- Updated dependencies [f833d3a]
|
|
34
|
+
- Updated dependencies [2a9513d]
|
|
35
|
+
- Updated dependencies [71be406]
|
|
36
|
+
- Updated dependencies [d22ae31]
|
|
37
|
+
- Updated dependencies [8d8094a]
|
|
38
|
+
- @object-ui/core@17.3.0
|
|
39
|
+
- @object-ui/components@17.3.0
|
|
40
|
+
- @object-ui/types@17.3.0
|
|
41
|
+
- @object-ui/react@17.3.0
|
|
42
|
+
|
|
3
43
|
## 17.2.0
|
|
4
44
|
|
|
5
45
|
### Patch Changes
|
package/dist/index.js
CHANGED
|
@@ -171,12 +171,12 @@ var y = ({ schema: a, dataSource: c, className: u, onMarkerClick: h, onRowClick:
|
|
|
171
171
|
}
|
|
172
172
|
if (!c || typeof c.find != "function") throw Error("DataSource required for object/api providers");
|
|
173
173
|
if (G?.provider === "object") {
|
|
174
|
-
let e = G.object, t = o(A?.fields), n =
|
|
174
|
+
let e = G.object, t = o(A?.fields), n = await c.find(e, {
|
|
175
175
|
$filter: a.filter,
|
|
176
176
|
$orderby: oe(a.sort),
|
|
177
177
|
...t.length > 0 ? { $expand: t } : {}
|
|
178
|
-
}));
|
|
179
|
-
E(
|
|
178
|
+
}), r = s(n);
|
|
179
|
+
E(r);
|
|
180
180
|
} else G?.provider === "api" && (console.warn("API provider not yet implemented for ObjectMap"), E([]));
|
|
181
181
|
D(!1);
|
|
182
182
|
} catch (e) {
|
package/dist/index.umd.cjs
CHANGED
|
@@ -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(),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});
|
|
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||!m.call(e,`default`)?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=await a.find(t,{$filter:e.filter,$orderby:v(e.sort),...r.length>0?{$expand:r}:{}}),o=(0,n.extractRecords)(i);_(o)}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": "17.
|
|
3
|
+
"version": "17.3.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "Map visualization plugin for Object UI",
|
|
@@ -24,26 +24,26 @@
|
|
|
24
24
|
}
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@objectstack/spec": "^17.0.0-rc.
|
|
28
|
-
"lucide-react": "^1.
|
|
29
|
-
"maplibre-gl": "^6.
|
|
30
|
-
"react-map-gl": "^8.1.
|
|
27
|
+
"@objectstack/spec": "^17.0.0-rc.2",
|
|
28
|
+
"lucide-react": "^1.28.0",
|
|
29
|
+
"maplibre-gl": "^6.1.0",
|
|
30
|
+
"react-map-gl": "^8.1.2",
|
|
31
31
|
"zod": "^4.4.3",
|
|
32
|
-
"@object-ui/
|
|
33
|
-
"@object-ui/
|
|
34
|
-
"@object-ui/
|
|
35
|
-
"@object-ui/
|
|
32
|
+
"@object-ui/components": "17.3.0",
|
|
33
|
+
"@object-ui/core": "17.3.0",
|
|
34
|
+
"@object-ui/react": "17.3.0",
|
|
35
|
+
"@object-ui/types": "17.3.0"
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
|
38
38
|
"react": "^18.0.0 || ^19.0.0",
|
|
39
39
|
"react-dom": "^18.0.0 || ^19.0.0"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@types/react": "19.2.
|
|
43
|
-
"@types/react-dom": "19.2.
|
|
44
|
-
"@vitejs/plugin-react": "^6.0.
|
|
42
|
+
"@types/react": "19.2.18",
|
|
43
|
+
"@types/react-dom": "19.2.4",
|
|
44
|
+
"@vitejs/plugin-react": "^6.0.5",
|
|
45
45
|
"typescript": "^6.0.3",
|
|
46
|
-
"vite": "^8.
|
|
46
|
+
"vite": "^8.2.0",
|
|
47
47
|
"vite-plugin-dts": "^5.0.3"
|
|
48
48
|
},
|
|
49
49
|
"keywords": [
|