react-listing-engine 0.6.10 → 0.7.1

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,25 @@
1
1
  # react-listing-engine
2
2
 
3
+ ## 0.7.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Fix on-map marker/popup click handling: call `google.maps.OverlayView.preventMapHitsAndGesturesFrom()` on the marker and popup overlay containers. Previously a real pointer click on an HTML overlay marker also registered as a Google Maps _map click_, which fired the background-click dismissal and immediately deselected the just-clicked marker — so the on-map popup opened and instantly closed. This also stops dragging over a marker or popup from panning the map underneath.
8
+
9
+ ## 0.7.0
10
+
11
+ ### Minor Changes
12
+
13
+ - Add Airbnb-style map interactivity.
14
+
15
+ - **Marker hover/selected repaint:** new `hovered` store state + `setHovered`, exposed on `useListingMap()`. `MapProvider.updateMarkerStates` toggles `rle-marker--selected` / `rle-marker--hovered` classes on marker containers (consumers style them). The highlight persists across marker recreation on pan/zoom.
16
+ - **On-map Popup:** the previously-inert `Popup` component slot now renders as an anchored `OverlayView` when a marker is selected. It stays anchored while panning and dismisses on the popup's close, `Esc`, or a map-background click. Backed by new `MapProvider.mountOverlay` and `MapProvider.onMapClick`.
17
+ - **Map controls slot:** `ListingApp` gains an optional `mapControls?: ReactNode` overlay slot, and `useListingMap()` gains `zoomIn()`, `zoomOut()`, `toggleFullscreen()`. Fullscreen targets the map wrapper so custom controls stay visible.
18
+
19
+ Consumers who don't use the new props/slots see no behavior change.
20
+
21
+ **Interface change (minor, pre-1.0):** the `MapProvider` interface gained required methods — `updateMarkerStates`, `mountOverlay`, `onMapClick`, `zoomIn`, `zoomOut`, `toggleFullscreen`. The built-in `googleProvider` and `FakeMapProvider` implement them; external custom `MapProvider` implementations must add them to compile against 0.7.0.
22
+
3
23
  ## 0.6.9
4
24
 
5
25
  ### Patch Changes
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2; var _class3; var _class4; var _class5;"use client";
2
+ var Q= (_class =class{__init() {this.listeners=new Set}constructor(e){;_class.prototype.__init.call(this);this.state=this.freezeState({filters:{...e.filters},results:{items:[],nextCursor:null},bounds:null,selection:null,hovered:null,pagination:{mode:_nullishCoalesce(e.mode, () => ("paged")),loading:!1},layers:{},points:{}})}getState(){return this.state}setFilters(e){this.setState({filters:{...this.state.filters,...e}})}setResults(e){this.setState({results:{items:[...e.items],nextCursor:e.nextCursor,total:e.total}})}appendResults(e){this.setState({results:{items:[...this.state.results.items,...e.items],nextCursor:e.nextCursor,total:e.total}})}setBounds(e){this.setState({bounds:e?{...e}:null})}setSelection(e){this.setState({selection:e})}setHovered(e){this.setState({hovered:e})}setLayerVisible(e,i){this.setState({layers:{...this.state.layers,[e]:i}})}setLoading(e){this.setState({pagination:{...this.state.pagination,loading:e}})}setPoints(e,i){this.setState({points:{...this.state.points,[e]:[...i]}})}subscribe(e){return this.listeners.add(e),()=>{this.listeners.delete(e)}}setState(e){this.state=this.freezeState({...this.state,...e}),this.notify()}notify(){for(let e of this.listeners)e()}freezeState(e){Object.freeze(e.filters),Object.freeze(e.results.items),Object.freeze(e.results),e.bounds&&Object.freeze(e.bounds),Object.freeze(e.pagination),Object.freeze(e.layers);for(let i of Object.values(e.points))Object.freeze(i);return Object.freeze(e.points),Object.freeze(e)}}, _class);var H= (_class2 =class{constructor() { _class2.prototype.__init2.call(this); }__init2() {this.defs=new Map}add(e){if(this.defs.has(e.key))throw new Error(`FilterRegistry: filter "${e.key}" is already registered`);return this.defs.set(e.key,{...e}),this}remove(e){return this.defs.delete(e),this}replace(e,i){if(!this.defs.has(e))throw new Error(`FilterRegistry: cannot replace unregistered filter "${e}"`);return this.defs.set(e,{...i,key:e}),this}reorder(e){let i=this.list(),r=e.filter(o=>this.defs.has(o));r.forEach((o,n)=>{this.defs.get(o).order=n});let s=new Set(r);return i.filter(o=>!s.has(o.key)).forEach((o,n)=>{o.order=r.length+n}),this}list(){return[...this.defs.values()].sort((e,i)=>e.order-i.order)}has(e){return this.defs.has(e)}toFilters(e){return this.list().filter(r=>Object.hasOwn(e,r.key)).map(r=>r.toParams(e[r.key])).reduce((r,s)=>({...r,...s}),{})}activeKeys(e){return this.list().filter(i=>_optionalChain([i, 'access', _2 => _2.isActive, 'optionalCall', _3 => _3(e)])).map(i=>i.key)}clearedParams(){return this.list().reduce((e,i)=>Object.assign(e,i.toParams(i.fromParams({}))),{})}}, _class2);var G= (_class3 =class{constructor() { _class3.prototype.__init3.call(this); }__init3() {this.defs=new Map}add(e){if(this.defs.has(e.id))throw new Error(`DatasetRegistry: dataset "${e.id}" is already registered`);return this.defs.set(e.id,{...e}),this}get(e){return this.defs.get(e)}has(e){return this.defs.has(e)}list(){return[...this.defs.values()]}visibleIds(){return this.list().filter(e=>_optionalChain([e, 'access', _4 => _4.visible, 'optionalCall', _5 => _5()])!==!1).map(e=>e.id)}}, _class3);var Z= (_class4 =class{constructor() { _class4.prototype.__init4.call(this); }__init4() {this.map=new Map}dispose(){this.map.clear()}emit(e){let i=this.map.get(e.type);if(i)for(let s of[...i])s(e);let r=this.map.get("*");if(r)for(let s of[...r])s(e)}on(e,i){let r=this.map.get(e);return r||(r=new Set,this.map.set(e,r)),r.add(i),()=>{r.delete(i)}}}, _class4);var Ce={pagination:"paged",pageSize:20,debounceMs:250};var X=class{constructor(e){this.options=Object.freeze({...Ce,...e})}};var J= (_class5 =class{__init5() {this.emitter=new Z}__init6() {this.debounceTimer=null}__init7() {this.debounceResolve=null}__init8() {this.queryToken=0}__init9() {this.pointsToken=0}constructor(e){;_class5.prototype.__init5.call(this);_class5.prototype.__init6.call(this);_class5.prototype.__init7.call(this);_class5.prototype.__init8.call(this);_class5.prototype.__init9.call(this);this.datasets=e.datasets,this.filters=_nullishCoalesce(e.filters, () => (new H)),this.map=e.map,this.config=new X(e.config);let i=_nullishCoalesce(e.primaryDatasetId, () => (_optionalChain([this, 'access', _6 => _6.datasets, 'access', _7 => _7.list, 'call', _8 => _8(), 'access', _9 => _9[0], 'optionalAccess', _10 => _10.id])));if(i==null||!this.datasets.has(i))throw new Error(`ListingEngine: primary dataset "${_nullishCoalesce(i, () => (""))}" is not registered \u2014 pass a valid primaryDatasetId or register at least one dataset`);this.primaryDatasetId=i,this.store=new Q({filters:_nullishCoalesce(e.initialFilters, () => ({})),mode:this.config.options.pagination})}get state(){return this.store.getState()}get options(){return this.config.options}applyFilters(e){this.store.setFilters(e),this.emitter.emit({type:"FiltersChanged",filters:this.currentFilters()}),this.clearDebounce();let i=++this.queryToken,r=this.config.options.debounceMs;return r<=0?this.runQuery(i):new Promise(s=>{this.debounceResolve=s,this.debounceTimer=setTimeout(()=>{this.debounceTimer=null,this.debounceResolve=null,s(this.runQuery(i))},r)})}async loadPage(){let e=this.state.results.nextCursor;if(e===null)return;let i=++this.queryToken,r=this.primaryDataset();this.store.setLoading(!0);try{let s=await r.adapter.list(this.currentFilters(),{cursor:e,limit:this.config.options.pageSize});if(i!==this.queryToken)return;this.config.options.pagination==="infinite"?this.store.appendResults(s):this.store.setResults(s),this.emitter.emit({type:"ResultsLoaded",datasetId:this.primaryDatasetId,count:s.items.length})}finally{i===this.queryToken&&this.store.setLoading(!1)}}async loadPoints(e){this.store.setBounds(e),this.emitter.emit({type:"BoundsChanged",bounds:e});let i=this.currentFilters(),r=++this.pointsToken;await Promise.allSettled(this.datasets.visibleIds().map(async s=>{let o=this.datasets.get(s);if(!o)return;let n=await o.adapter.getPoints(i,e);r===this.pointsToken&&this.store.setPoints(s,n)}))}selectPoint(e,i){this.store.setSelection(i);let r=_optionalChain([this, 'access', _11 => _11.state, 'access', _12 => _12.points, 'access', _13 => _13[e], 'optionalAccess', _14 => _14.find, 'call', _15 => _15(s=>s.id===i)]);r&&this.emitter.emit({type:"PointClicked",datasetId:e,id:r.id,entity:r.entity})}setHovered(e,i){this.store.setHovered(i)}toggleLayer(e){let r=!(_nullishCoalesce(this.state.layers[e], () => (!0)));this.store.setLayerVisible(e,r),this.emitter.emit({type:"LayerToggled",datasetId:e,visible:r})}subscribe(e){return this.store.subscribe(e)}on(e,i){return this.emitter.on(e,i)}dispose(){this.clearDebounce(),this.emitter.dispose()}async runQuery(e){if(e!==this.queryToken)return;let i=this.primaryDataset();this.store.setLoading(!0);try{let r=await i.adapter.list(this.currentFilters(),{cursor:null,limit:this.config.options.pageSize});if(e!==this.queryToken)return;this.store.setResults(r),this.emitter.emit({type:"ResultsLoaded",datasetId:this.primaryDatasetId,count:r.items.length})}finally{e===this.queryToken&&this.store.setLoading(!1)}}primaryDataset(){return this.datasets.get(this.primaryDatasetId)}currentFilters(){return this.store.getState().filters}clearDebounce(){this.debounceTimer!==null&&(clearTimeout(this.debounceTimer),this.debounceTimer=null),this.debounceResolve!==null&&(this.debounceResolve(),this.debounceResolve=null)}}, _class5);function Se(...t){let e={config:{},filters:new H,datasets:new G};for(let i of t)i(e);return e}var Ie=t=>e=>{e.config={...e.config,...t}},we= exports.j =t=>e=>{e.map=t},ke= exports.k =t=>e=>{e.datasets.add(t)},Ee= exports.l =t=>e=>{t(e.filters)},yi= exports.m =t=>e=>{e.urlSync=t},xe= exports.n =t=>e=>{e.initialFilters=t},vi= exports.o =t=>e=>{e.primaryDatasetId=t};var _react = require('react');var _jsxruntime = require('react/jsx-runtime');function nt(t){return String(_nullishCoalesce(_optionalChain([t, 'optionalAccess', _16 => _16.title]), () => ("")))}var st=({item:t})=>_jsxruntime.jsx.call(void 0, "div",{children:nt(t)}),ot=()=>_jsxruntime.jsx.call(void 0, "div",{}),le= exports.p =()=>_jsxruntime.jsx.call(void 0, "div",{}),at=({children:t})=>_jsxruntime.jsx.call(void 0, "div",{children:t}),lt=({children:t})=>_jsxruntime.jsx.call(void 0, "div",{children:t}),dt=({value:t,onChange:e,placeholder:i})=>_jsxruntime.jsx.call(void 0, "input",{type:"search",value:t,placeholder:i,onChange:r=>e(r.target.value),"aria-label":_nullishCoalesce(i, () => ("Search"))}),pt=()=>_jsxruntime.jsx.call(void 0, "div",{role:"status",children:"No results"}),ct=()=>_jsxruntime.jsx.call(void 0, "div",{role:"status","aria-busy":"true",children:"Loading\u2026"}),ut=({count:t})=>_jsxruntime.jsxs.call(void 0, "div",{children:[t," results"]}),mt=({children:t})=>_jsxruntime.jsx.call(void 0, "div",{children:t}),C={Card:st,Marker:ot,Popup:le,Sidebar:at,FilterPanel:lt,Search:dt,Empty:pt,Loading:ct,ResultHeader:ut,Toolbar:mt},Ne=_react.createContext.call(void 0, C);function Re(t){let{Card:e,Marker:i,Popup:r,Sidebar:s,FilterPanel:o,Search:n,Empty:a,Loading:d,ResultHeader:l,Toolbar:c,children:h}=t,b={Card:_nullishCoalesce(e, () => (C.Card)),Marker:_nullishCoalesce(i, () => (C.Marker)),Popup:_nullishCoalesce(r, () => (C.Popup)),Sidebar:_nullishCoalesce(s, () => (C.Sidebar)),FilterPanel:_nullishCoalesce(o, () => (C.FilterPanel)),Search:_nullishCoalesce(n, () => (C.Search)),Empty:_nullishCoalesce(a, () => (C.Empty)),Loading:_nullishCoalesce(d, () => (C.Loading)),ResultHeader:_nullishCoalesce(l, () => (C.ResultHeader)),Toolbar:_nullishCoalesce(c, () => (C.Toolbar))};return _jsxruntime.jsx.call(void 0, Ne.Provider,{value:b,children:h})}function P(){return _react.useContext.call(void 0, Ne)}var Y=_react.createContext.call(void 0, null);function g(){let t=_react.useContext.call(void 0, Y);if(t===null)throw new Error("useListing must be used within a <ListingProvider>");return t}function I(){let t=g(),e=_react.useCallback.call(void 0, r=>t.subscribe(r),[t]),i=_react.useCallback.call(void 0, ()=>t.state,[t]);return _react.useSyncExternalStore.call(void 0, e,i,i)}function ee(){let t=g(),e=I(),i=_react.useCallback.call(void 0, s=>t.applyFilters(s),[t]),r=_react.useCallback.call(void 0, (s,o)=>t.applyFilters({[s]:o}),[t]);return{filters:e.filters,set:i,setField:r}}function de({className:t,groupClassName:e,hideLabels:i}={}){let r=g(),{FilterPanel:s}=P(),{filters:o}=ee();return _jsxruntime.jsx.call(void 0, s,{children:_jsxruntime.jsx.call(void 0, "div",{className:_nullishCoalesce(t, () => ("space-y-5")),children:r.filters.list().map(n=>{if(typeof n.render=="string")return _jsxruntime.jsx.call(void 0, "div",{"data-filter":n.key,className:e},n.key);let a=n.render;return _jsxruntime.jsxs.call(void 0, "div",{className:e,children:[n.label&&!i&&_jsxruntime.jsx.call(void 0, "div",{className:"mb-1.5 text-[13px] font-medium text-foreground",children:n.label}),_jsxruntime.jsx.call(void 0, a,{value:n.fromParams(o),onChange:d=>{r.applyFilters(n.toParams(d))}})]},n.key)})})})}function z(){return I().results}function Lt(t,e){if(t&&typeof t=="object"&&"id"in t){let i=t.id;if(typeof i=="string"||typeof i=="number")return i}return e}function Oe({className:t}={}){let e=g(),{items:i}=z(),{pagination:r,selection:s}=I(),{Card:o,Empty:n,Loading:a}=P();return r.loading&&i.length===0?_jsxruntime.jsx.call(void 0, a,{}):i.length===0?_jsxruntime.jsx.call(void 0, n,{}):_jsxruntime.jsx.call(void 0, "div",{role:"list",className:t,children:i.map((d,l)=>{let c=Lt(d,l);return _jsxruntime.jsx.call(void 0, o,{item:d,selected:s===c,onSelect:()=>e.selectPoint(e.primaryDatasetId,c)},c)})})}var _reactdom = require('react-dom');var Pt={west:-179.9,south:-85,east:179.9,north:85},Be=.1,Ae=.02;function Tt(t){if(t.length===0)return null;let e=t[0].lng,i=t[0].lng,r=t[0].lat,s=t[0].lat;for(let{lat:a,lng:d}of t)d<e&&(e=d),d>i&&(i=d),a<r&&(r=a),a>s&&(s=a);let o=s>r?(s-r)*Be:Ae,n=i>e?(i-e)*Be:Ae;return{west:e-n,east:i+n,south:r-o,north:s+o}}function ze(t){let{center:e,zoom:i,fallback:r,mapControls:s}=t,o=g(),n=I(),a=_react.useRef.call(void 0, null),d=_react.useRef.call(void 0, null),l=_react.useRef.call(void 0, null),[c,h]=_react.useState.call(void 0, !1),b=_react.useRef.call(void 0, !1),w=_react.useRef.call(void 0, !1),k=_react.useRef.call(void 0, !1),p=o.map;_react.useEffect.call(void 0, ()=>{let L=l.current;if(!p||!L)return;let f=[];for(let u of Object.keys(n.points)){if(n.layers[u]===!1)continue;let y=o.datasets.get(u),R=_nullishCoalesce(n.points[u], () => ([])),ae={id:u,markers:R.map(M=>({id:M.id,position:M.position,iconUrl:_optionalChain([y, 'optionalAccess', _17 => _17.marker, 'access', _18 => _18.iconUrl, 'optionalCall', _19 => _19(M.entity)]),element:_optionalChain([y, 'optionalAccess', _20 => _20.marker, 'access', _21 => _21.element, 'optionalCall', _22 => _22(M.entity)])})),clustering:_optionalChain([y, 'optionalAccess', _23 => _23.clustering]),onMarkerClick:M=>o.selectPoint(u,M)};f.push(p.renderLayer(L,ae))}return()=>{f.forEach(u=>u())}},[o,p,c,n.points,n.layers]),_react.useEffect.call(void 0, ()=>{if(!a.current||!p)return;let L=a.current,f=!1,u=null;return(async()=>{let y=await p.mount(L,{center:e,zoom:i,fullscreenTarget:_nullishCoalesce(d.current, () => (void 0))});if(f){p.destroy(y);return}l.current=y,u=p.onBoundsChange(y,R=>{k.current?k.current=!1:w.current=!0,o.loadPoints(R)}),h(!0),o.loadPoints(Pt)})(),()=>{f=!0,_optionalChain([u, 'optionalCall', _24 => _24()]),l.current&&(p.destroy(l.current),l.current=null),h(!1)}},[o,p]),_react.useEffect.call(void 0, ()=>{let L=l.current;if(!p||!L||e||b.current||w.current)return;let f=[];for(let y of Object.keys(n.points))if(n.layers[y]!==!1)for(let R of _nullishCoalesce(n.points[y], () => ([])))f.push(R.position);let u=Tt(f);u&&(b.current=!0,k.current=!0,p.fitBounds(L,u))},[p,e,c,n.points,n.layers]),_react.useEffect.call(void 0, ()=>{_optionalChain([p, 'optionalAccess', _25 => _25.updateMarkerStates, 'call', _26 => _26(n.selection,n.hovered)])},[p,c,n.selection,n.hovered]);let{Popup:F}=P(),O=F!==le,_=_nullishCoalesce(n.points[o.primaryDatasetId], () => ([])),A=n.selection!=null?_.find(L=>L.id===n.selection):void 0,[V,j]=_react.useState.call(void 0, null),N=_react.useRef.call(void 0, A);return N.current=A,_react.useEffect.call(void 0, ()=>{let L=l.current;if(!p||!L||!O)return;let f=N.current;if(!f)return;let u=p.mountOverlay(f.position);j({entity:f.entity,position:f.position,container:u.container});let y=()=>o.selectPoint(o.primaryDatasetId,null),R=M=>{M.key==="Escape"&&y()};document.addEventListener("keydown",R);let ae=p.onMapClick(y);return()=>{document.removeEventListener("keydown",R),ae(),u.unmount(),j(null)}},[o,p,c,n.selection,O]),_jsxruntime.jsxs.call(void 0, "div",{ref:d,className:"relative h-full min-h-0 w-full",children:[_jsxruntime.jsxs.call(void 0, "div",{ref:a,className:!p&&r?"flex h-full min-h-0 w-full items-center justify-center":"h-full min-h-0 w-full",children:[!p&&r,O&&V?_reactdom.createPortal.call(void 0, _jsxruntime.jsx.call(void 0, F,{entity:V.entity,onClose:()=>o.selectPoint(o.primaryDatasetId,null)}),V.container):null]}),s!=null&&_jsxruntime.jsx.call(void 0, "div",{className:"pointer-events-none absolute inset-0",children:_jsxruntime.jsx.call(void 0, "div",{className:"pointer-events-auto",children:s})})]})}function Ke(){let t=g(),{results:e,pagination:i}=I();return e.nextCursor==null?null:_jsxruntime.jsx.call(void 0, "button",{type:"button",disabled:i.loading,onClick:()=>{t.loadPage()},children:"Load more"})}function Ue(){let{items:t,total:e}=z(),{ResultHeader:i}=P();return _jsxruntime.jsx.call(void 0, i,{count:t.length,total:e})}function Ve(t,e){let i=g(),r=_react.useRef.call(void 0, e);r.current=e,_react.useEffect.call(void 0, ()=>i.on(t,s=>r.current(s)),[i,t])}function We(t){let{children:e,...i}=t,[r]=_react.useState.call(void 0, ()=>i),[s,o]=_react.useState.call(void 0, null);return _react.useEffect.call(void 0, ()=>{let n=new J({datasets:r.datasets,filters:r.filters,config:r.config,map:r.map,initialFilters:r.initialFilters,primaryDatasetId:r.primaryDatasetId});return r.urlSync&&r.urlSync.start(n),o(n),()=>{r.urlSync&&r.urlSync.stop(),n.dispose(),o(a=>a===n?null:a)}},[r]),s?_jsxruntime.jsx.call(void 0, Y.Provider,{value:s,children:e}):null}function K(t){return typeof t!="number"?t:new Intl.NumberFormat("en-US",{style:"currency",currency:"USD",maximumFractionDigits:0}).format(t)}function Et(t){return t?"rle-card rle-card--selected":"rle-card"}function ce({item:t,selected:e,onSelect:i}){let r=_nullishCoalesce(t, () => ({})),s=Et(e),o=_jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment,{children:[r.imageUrl?_jsxruntime.jsx.call(void 0, "img",{src:r.imageUrl,alt:_nullishCoalesce(r.title, () => ("")),className:"rle-card-media"}):_jsxruntime.jsx.call(void 0, "div",{className:"rle-card-media rle-card-media--placeholder","aria-hidden":"true"}),_jsxruntime.jsxs.call(void 0, "div",{className:"rle-card-body",children:[r.title&&_jsxruntime.jsx.call(void 0, "span",{className:"rle-card-title",children:r.title}),r.subtitle&&_jsxruntime.jsx.call(void 0, "span",{className:"rle-card-address",children:r.subtitle}),r.badge&&_jsxruntime.jsx.call(void 0, "div",{className:"rle-card-info",children:_jsxruntime.jsx.call(void 0, "span",{className:"rle-card-info-item",children:r.badge})}),r.price!=null&&_jsxruntime.jsx.call(void 0, "span",{className:"rle-card-price",children:K(r.price)})]})]});return i?_jsxruntime.jsx.call(void 0, "button",{type:"button",onClick:i,"aria-pressed":_nullishCoalesce(e, () => (!1)),className:s,children:o}):_jsxruntime.jsx.call(void 0, "article",{className:s,children:o})}function ue(t){return _jsxruntime.jsxs.call(void 0, "div",{role:"status",className:"rle-empty",children:[_jsxruntime.jsxs.call(void 0, "svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:1.5,strokeLinecap:"round",strokeLinejoin:"round",className:"rle-empty-icon","aria-hidden":"true",children:[_jsxruntime.jsx.call(void 0, "circle",{cx:"11",cy:"11",r:"7"}),_jsxruntime.jsx.call(void 0, "path",{d:"m21 21-4.3-4.3"})]}),_jsxruntime.jsx.call(void 0, "p",{className:"rle-empty-title",children:"No results"}),_jsxruntime.jsx.call(void 0, "p",{className:"rle-empty-hint",children:"Try adjusting your filters or search terms."})]})}function me({children:t}){return _jsxruntime.jsx.call(void 0, "div",{className:"rle-filter-panel",children:t})}function ge(t){return _jsxruntime.jsx.call(void 0, "div",{className:"rle-loading",role:"status","aria-busy":"true","aria-label":"Loading results",children:Array.from({length:3}).map((e,i)=>_jsxruntime.jsxs.call(void 0, "div",{className:"rle-loading-item",children:[_jsxruntime.jsx.call(void 0, "div",{className:"rle-skeleton",style:{aspectRatio:"4 / 3",width:"100%"}}),_jsxruntime.jsx.call(void 0, "div",{className:"rle-skeleton",style:{height:16,width:"65%"}}),_jsxruntime.jsx.call(void 0, "div",{className:"rle-skeleton",style:{height:12,width:"35%"}})]},i))})}function fe({point:t}){let e=_nullishCoalesce(t.entity, () => ({}));return _jsxruntime.jsx.call(void 0, "span",{className:"rle-pin",children:e.price!=null?K(e.price):""})}function ve({entity:t,onClose:e}){let i=_nullishCoalesce(t, () => ({}));return _jsxruntime.jsxs.call(void 0, "div",{className:"rle-popup",role:"group","aria-label":"Location details",children:[_jsxruntime.jsx.call(void 0, "button",{type:"button",onClick:e,"aria-label":"Close",className:"rle-popup-close",children:_jsxruntime.jsxs.call(void 0, "svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round",width:"16",height:"16","aria-hidden":"true",children:[_jsxruntime.jsx.call(void 0, "path",{d:"M18 6 6 18"}),_jsxruntime.jsx.call(void 0, "path",{d:"m6 6 12 12"})]})}),_jsxruntime.jsxs.call(void 0, "div",{children:[i.title&&_jsxruntime.jsx.call(void 0, "div",{className:"rle-card-title",children:i.title}),i.subtitle&&_jsxruntime.jsx.call(void 0, "div",{className:"rle-card-address",children:i.subtitle}),i.price!=null&&_jsxruntime.jsx.call(void 0, "div",{className:"rle-card-price",children:K(i.price)})]})]})}function he({count:t,total:e}){let i=e!=null&&e!==t?`${t} of ${e} results`:`${t} results`;return _jsxruntime.jsx.call(void 0, "div",{className:"rle-result-header",children:i})}function Le({value:t,onChange:e,placeholder:i}){return _jsxruntime.jsx.call(void 0, "input",{type:"search",value:t,placeholder:i,onChange:r=>e(r.target.value),"aria-label":_nullishCoalesce(i, () => ("Search")),className:"rle-input"})}function be({children:t}){return _jsxruntime.jsx.call(void 0, "aside",{className:"rle-sidebar",children:t})}function Pe({children:t}){return _jsxruntime.jsx.call(void 0, "div",{className:"rle-toolbar",children:t})}var Qe={Card:ce,Marker:fe,Popup:ve,Sidebar:be,FilterPanel:me,Search:Le,Empty:ue,Loading:ge,ResultHeader:he,Toolbar:Pe};function Ge({view:t,onViewChange:e}){return _jsxruntime.jsx.call(void 0, "nav",{className:"rle-bottom-nav","aria-label":"Listing navigation",children:_jsxruntime.jsxs.call(void 0, "div",{className:"rle-viewtoggle",role:"group","aria-label":"View",children:[_jsxruntime.jsxs.call(void 0, "button",{type:"button",className:`rle-viewtoggle__btn${t==="list"?" rle-viewtoggle__btn--active":""}`,"aria-pressed":t==="list",onClick:()=>e("list"),children:[_jsxruntime.jsx.call(void 0, At,{}),"List"]}),_jsxruntime.jsxs.call(void 0, "button",{type:"button",className:`rle-viewtoggle__btn${t==="map"?" rle-viewtoggle__btn--active":""}`,"aria-pressed":t==="map",onClick:()=>e("map"),children:[_jsxruntime.jsx.call(void 0, Ht,{}),"Map"]})]})})}function At(){return _jsxruntime.jsxs.call(void 0, "svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round",width:"16",height:"16","aria-hidden":"true",children:[_jsxruntime.jsx.call(void 0, "line",{x1:"8",y1:"6",x2:"20",y2:"6"}),_jsxruntime.jsx.call(void 0, "line",{x1:"8",y1:"12",x2:"20",y2:"12"}),_jsxruntime.jsx.call(void 0, "line",{x1:"8",y1:"18",x2:"20",y2:"18"}),_jsxruntime.jsx.call(void 0, "line",{x1:"4",y1:"6",x2:"4.01",y2:"6"}),_jsxruntime.jsx.call(void 0, "line",{x1:"4",y1:"12",x2:"4.01",y2:"12"}),_jsxruntime.jsx.call(void 0, "line",{x1:"4",y1:"18",x2:"4.01",y2:"18"})]})}function Ht(){return _jsxruntime.jsxs.call(void 0, "svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round",width:"16",height:"16","aria-hidden":"true",children:[_jsxruntime.jsx.call(void 0, "polygon",{points:"1 6 8 3 16 6 23 3 23 18 16 21 8 18 1 21 1 6"}),_jsxruntime.jsx.call(void 0, "line",{x1:"8",y1:"3",x2:"8",y2:"18"}),_jsxruntime.jsx.call(void 0, "line",{x1:"16",y1:"6",x2:"16",y2:"21"})]})}function Xe({open:t,onOpenChange:e,title:i,children:r,footer:s}){let o=_react.useRef.call(void 0, null),[n,a]=_react.useState.call(void 0, !1),[d,l]=_react.useState.call(void 0, !1);return _react.useEffect.call(void 0, ()=>{if(!t){l(!1),a(!1);return}a(!0);let c=requestAnimationFrame(()=>l(!0));return()=>cancelAnimationFrame(c)},[t]),_react.useEffect.call(void 0, ()=>{if(!n)return;let c=document.body.style.overflow;return document.body.style.overflow="hidden",()=>{document.body.style.overflow=c}},[n]),_react.useEffect.call(void 0, ()=>{if(!n)return;_optionalChain([o, 'access', _27 => _27.current, 'optionalAccess', _28 => _28.focus, 'call', _29 => _29()]);function c(h){h.key==="Escape"&&e(!1)}return document.addEventListener("keydown",c),()=>document.removeEventListener("keydown",c)},[n,e]),!n||typeof document>"u"?null:_reactdom.createPortal.call(void 0, _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment,{children:[_jsxruntime.jsx.call(void 0, "div",{className:`rle-sheet-backdrop${d?" rle-sheet-backdrop--open":""}`,onClick:()=>e(!1),"aria-hidden":"true"}),_jsxruntime.jsxs.call(void 0, "div",{ref:o,className:`rle-sheet${d?" rle-sheet--open":""}`,role:"dialog","aria-modal":"true","aria-label":i,tabIndex:-1,children:[_jsxruntime.jsx.call(void 0, "div",{className:"rle-sheet__handle","aria-hidden":"true"}),_jsxruntime.jsxs.call(void 0, "div",{className:"rle-sheet__header",children:[i&&_jsxruntime.jsx.call(void 0, "div",{className:"rle-sheet__title",children:i}),_jsxruntime.jsx.call(void 0, "button",{type:"button",className:"rle-sheet__close",onClick:()=>e(!1),"aria-label":"Close",children:_jsxruntime.jsx.call(void 0, Ut,{})})]}),_jsxruntime.jsx.call(void 0, "div",{className:"rle-sheet__body",children:r}),s&&_jsxruntime.jsx.call(void 0, "div",{className:"rle-sheet__footer",children:s})]})]}),document.body)}function Ut(){return _jsxruntime.jsxs.call(void 0, "svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round",width:"16",height:"16","aria-hidden":"true",children:[_jsxruntime.jsx.call(void 0, "path",{d:"M18 6 6 18"}),_jsxruntime.jsx.call(void 0, "path",{d:"m6 6 12 12"})]})}function Je({search:t,onFiltersClick:e,filterCount:i=0,action:r}){let{Search:s}=P();return _jsxruntime.jsxs.call(void 0, "header",{className:"rle-mobile-header",children:[t&&_jsxruntime.jsx.call(void 0, "div",{className:"rle-mobile-header__search",children:_jsxruntime.jsx.call(void 0, s,{value:t.value,onChange:t.onChange,placeholder:t.placeholder})}),_jsxruntime.jsxs.call(void 0, "button",{type:"button",className:"rle-btn rle-mobile-header__btn",onClick:e,children:[_jsxruntime.jsx.call(void 0, $t,{}),_jsxruntime.jsx.call(void 0, "span",{children:"Filters"}),i>0&&_jsxruntime.jsx.call(void 0, "span",{className:"rle-mobile-header__count",children:i})]}),r&&_jsxruntime.jsx.call(void 0, "button",{type:"button",className:"rle-btn rle-mobile-header__btn rle-mobile-header__btn--icon",onClick:r.onClick,"aria-label":r.label,children:_nullishCoalesce(r.icon, () => (_jsxruntime.jsx.call(void 0, Wt,{})))})]})}function $t(){return _jsxruntime.jsxs.call(void 0, "svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:[_jsxruntime.jsx.call(void 0, "line",{x1:"4",y1:"6",x2:"20",y2:"6"}),_jsxruntime.jsx.call(void 0, "circle",{cx:"9",cy:"6",r:"2",fill:"currentColor",stroke:"none"}),_jsxruntime.jsx.call(void 0, "line",{x1:"4",y1:"12",x2:"20",y2:"12"}),_jsxruntime.jsx.call(void 0, "circle",{cx:"15",cy:"12",r:"2",fill:"currentColor",stroke:"none"}),_jsxruntime.jsx.call(void 0, "line",{x1:"4",y1:"18",x2:"20",y2:"18"}),_jsxruntime.jsx.call(void 0, "circle",{cx:"11",cy:"18",r:"2",fill:"currentColor",stroke:"none"})]})}function Wt(){return _jsxruntime.jsxs.call(void 0, "svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:[_jsxruntime.jsx.call(void 0, "line",{x1:"12",y1:"5",x2:"12",y2:"19"}),_jsxruntime.jsx.call(void 0, "line",{x1:"5",y1:"12",x2:"19",y2:"12"})]})}var jt=_jsxruntime.jsx.call(void 0, "div",{className:"rle-empty",children:"Map unavailable"});function Qt(){let t=_react.useRef.call(void 0, null),[e,i]=_react.useState.call(void 0, !0),[r,s]=_react.useState.call(void 0, !0);return _react.useEffect.call(void 0, ()=>{let o=t.current;if(!o)return;let n=()=>{let{clientWidth:h,scrollLeft:b,scrollWidth:w}=o;i(b<=0),s(b+h>=w-1)},a=0,d=()=>{a||(a=requestAnimationFrame(()=>{a=0,n()}))};n(),o.addEventListener("scroll",n,{passive:!0});let l,c;return typeof ResizeObserver<"u"&&(l=new ResizeObserver(n),l.observe(o)),typeof MutationObserver<"u"&&(c=new MutationObserver(d),c.observe(o,{characterData:!0,childList:!0,subtree:!0})),()=>{o.removeEventListener("scroll",n),_optionalChain([l, 'optionalAccess', _30 => _30.disconnect, 'call', _31 => _31()]),_optionalChain([c, 'optionalAccess', _32 => _32.disconnect, 'call', _33 => _33()]),a&&cancelAnimationFrame(a)}},[]),{atEnd:r,atStart:e,ref:t}}function et({search:t,toolbarEnd:e,mobileAction:i,autoFetch:r=!0,hasMap:s,mapCenter:o,mapZoom:n,mapControls:a,className:d}){let l=g(),{Search:c}=P(),h=z(),{filters:b,set:w}=ee(),k=_nullishCoalesce(s, () => (l.map!=null)),[p,F]=_react.useState.call(void 0, "list"),[O,_]=_react.useState.call(void 0, !1),{atEnd:A,atStart:V,ref:j}=Qt(),N=t?{value:String(_nullishCoalesce(b[t.filterKey], () => (""))),onChange:y=>{w({[t.filterKey]:y||void 0})},placeholder:t.placeholder}:void 0;_react.useEffect.call(void 0, ()=>{r!==!1&&l.applyFilters({})},[l,r]);let L=()=>{w(l.filters.clearedParams())},f=l.filters.activeKeys(b).length,u=_nullishCoalesce(h.total, () => (h.items.length));return _jsxruntime.jsxs.call(void 0, "div",{className:d?`rle-app ${d}`:"rle-app",children:[_jsxruntime.jsxs.call(void 0, "div",{className:"rle-filter-bar",children:[_jsxruntime.jsxs.call(void 0, "div",{className:"rle-filter-bar__scroll",ref:j,children:[N&&_jsxruntime.jsx.call(void 0, "div",{className:"rle-filter-bar__search",children:_jsxruntime.jsx.call(void 0, c,{value:N.value,onChange:N.onChange,placeholder:N.placeholder})}),_jsxruntime.jsx.call(void 0, de,{className:"rle-filters-row",groupClassName:"rle-filter-group",hideLabels:!0})]}),!V&&_jsxruntime.jsx.call(void 0, "div",{className:"rle-filter-bar__fade rle-filter-bar__fade--start","aria-hidden":"true"}),!A&&_jsxruntime.jsx.call(void 0, "div",{className:"rle-filter-bar__fade rle-filter-bar__fade--end","aria-hidden":"true"})]}),_jsxruntime.jsx.call(void 0, Je,{search:N,onFiltersClick:()=>_(!0),filterCount:f,action:i}),_jsxruntime.jsxs.call(void 0, "div",{className:`rle-body ${k?"rle-split":"rle-body--list-only"}`,"data-mobile-view":p,children:[_jsxruntime.jsxs.call(void 0, "div",{className:"rle-list",children:[_jsxruntime.jsxs.call(void 0, "div",{className:"rle-list-header",children:[_jsxruntime.jsx.call(void 0, Ue,{}),e&&_jsxruntime.jsx.call(void 0, "div",{className:"rle-list-header__toolbar",children:e})]}),_jsxruntime.jsx.call(void 0, Oe,{className:"rle-list-grid"}),_jsxruntime.jsx.call(void 0, Ke,{})]}),k&&_jsxruntime.jsx.call(void 0, "div",{className:"rle-map",children:_jsxruntime.jsx.call(void 0, ze,{center:o,zoom:n,fallback:jt,mapControls:a})})]}),k&&_jsxruntime.jsx.call(void 0, Ge,{view:p,onViewChange:F}),_jsxruntime.jsx.call(void 0, Xe,{title:"Filters",open:O,onOpenChange:_,footer:_jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment,{children:[_jsxruntime.jsx.call(void 0, "button",{type:"button",className:"rle-btn rle-btn--ghost",onClick:L,children:"Clear all"}),_jsxruntime.jsxs.call(void 0, "button",{type:"button",className:"rle-btn rle-btn--primary",onClick:()=>_(!1),children:["Show ",u," results"]})]}),children:_jsxruntime.jsx.call(void 0, de,{className:"rle-filter-stack",groupClassName:"rle-filter-group"})})]})}function tt(t){return"provider"in t}function Yt(t){let e=t!=null&&!tt(t),i=e?t.apiKey:void 0,r=e?t.mapId:void 0,s=e?t.mapOptions:void 0,o=e?t.styles:void 0,[n,a]=_react.useState.call(void 0, ()=>!t||tt(t)?{ready:!0,provider:_optionalChain([t, 'optionalAccess', _34 => _34.provider])}:{ready:!1});return _react.useEffect.call(void 0, ()=>{if(!i)return;let d=!1;return Promise.resolve().then(() => _interopRequireWildcard(require("./maps/google/index.cjs"))).then(({googleProvider:l})=>{d||a({ready:!0,provider:l({apiKey:i,mapId:r,mapOptions:s,styles:o})})}),()=>{d=!0}},[i,r]),n}function ei({onFiltersChange:t}){let e=_react.useRef.call(void 0, t);return e.current=t,Ve("FiltersChanged",i=>{i.type==="FiltersChanged"&&e.current(i.filters)}),null}function Pn(t){let{datasets:e,filters:i,map:r,components:s,initialFilters:o,onFiltersChange:n,mobileAction:a,search:d,toolbarEnd:l,mapControls:c,config:h,autoFetch:b,className:w}=t,{ready:k,provider:p}=Yt(r);if(!k)return null;let F=[];for(let A of e)F.push(ke(A));i&&F.push(Ee(i)),p&&F.push(we(p)),o&&F.push(xe(o)),h&&F.push(Ie(h));let O=Se(...F),_={...Qe,...s};return _jsxruntime.jsxs.call(void 0, We,{...O,children:[n&&_jsxruntime.jsx.call(void 0, ei,{onFiltersChange:n}),_jsxruntime.jsx.call(void 0, Re,{..._,children:_jsxruntime.jsx.call(void 0, et,{className:w,search:d,toolbarEnd:l,mobileAction:a,autoFetch:b,mapCenter:_optionalChain([r, 'optionalAccess', _35 => _35.center]),mapZoom:_optionalChain([r, 'optionalAccess', _36 => _36.zoom]),mapControls:c})})]})}exports.a = Q; exports.b = H; exports.c = G; exports.d = Z; exports.e = Ce; exports.f = X; exports.g = J; exports.h = Se; exports.i = Ie; exports.j = we; exports.k = ke; exports.l = Ee; exports.m = yi; exports.n = xe; exports.o = vi; exports.p = le; exports.q = Re; exports.r = P; exports.s = Y; exports.t = g; exports.u = I; exports.v = ee; exports.w = de; exports.x = z; exports.y = Oe; exports.z = ze; exports.A = Ke; exports.B = Ue; exports.C = Ve; exports.D = We; exports.E = ce; exports.F = ue; exports.G = me; exports.H = ge; exports.I = fe; exports.J = ve; exports.K = he; exports.L = Le; exports.M = be; exports.N = Pe; exports.O = Qe; exports.P = Ge; exports.Q = Xe; exports.R = et; exports.S = Pn;
@@ -0,0 +1,2 @@
1
+ "use client";
2
+ var Q=class{state;listeners=new Set;constructor(e){this.state=this.freezeState({filters:{...e.filters},results:{items:[],nextCursor:null},bounds:null,selection:null,hovered:null,pagination:{mode:e.mode??"paged",loading:!1},layers:{},points:{}})}getState(){return this.state}setFilters(e){this.setState({filters:{...this.state.filters,...e}})}setResults(e){this.setState({results:{items:[...e.items],nextCursor:e.nextCursor,total:e.total}})}appendResults(e){this.setState({results:{items:[...this.state.results.items,...e.items],nextCursor:e.nextCursor,total:e.total}})}setBounds(e){this.setState({bounds:e?{...e}:null})}setSelection(e){this.setState({selection:e})}setHovered(e){this.setState({hovered:e})}setLayerVisible(e,i){this.setState({layers:{...this.state.layers,[e]:i}})}setLoading(e){this.setState({pagination:{...this.state.pagination,loading:e}})}setPoints(e,i){this.setState({points:{...this.state.points,[e]:[...i]}})}subscribe(e){return this.listeners.add(e),()=>{this.listeners.delete(e)}}setState(e){this.state=this.freezeState({...this.state,...e}),this.notify()}notify(){for(let e of this.listeners)e()}freezeState(e){Object.freeze(e.filters),Object.freeze(e.results.items),Object.freeze(e.results),e.bounds&&Object.freeze(e.bounds),Object.freeze(e.pagination),Object.freeze(e.layers);for(let i of Object.values(e.points))Object.freeze(i);return Object.freeze(e.points),Object.freeze(e)}};var H=class{defs=new Map;add(e){if(this.defs.has(e.key))throw new Error(`FilterRegistry: filter "${e.key}" is already registered`);return this.defs.set(e.key,{...e}),this}remove(e){return this.defs.delete(e),this}replace(e,i){if(!this.defs.has(e))throw new Error(`FilterRegistry: cannot replace unregistered filter "${e}"`);return this.defs.set(e,{...i,key:e}),this}reorder(e){let i=this.list(),r=e.filter(o=>this.defs.has(o));r.forEach((o,n)=>{this.defs.get(o).order=n});let s=new Set(r);return i.filter(o=>!s.has(o.key)).forEach((o,n)=>{o.order=r.length+n}),this}list(){return[...this.defs.values()].sort((e,i)=>e.order-i.order)}has(e){return this.defs.has(e)}toFilters(e){return this.list().filter(r=>Object.hasOwn(e,r.key)).map(r=>r.toParams(e[r.key])).reduce((r,s)=>({...r,...s}),{})}activeKeys(e){return this.list().filter(i=>i.isActive?.(e)).map(i=>i.key)}clearedParams(){return this.list().reduce((e,i)=>Object.assign(e,i.toParams(i.fromParams({}))),{})}};var G=class{defs=new Map;add(e){if(this.defs.has(e.id))throw new Error(`DatasetRegistry: dataset "${e.id}" is already registered`);return this.defs.set(e.id,{...e}),this}get(e){return this.defs.get(e)}has(e){return this.defs.has(e)}list(){return[...this.defs.values()]}visibleIds(){return this.list().filter(e=>e.visible?.()!==!1).map(e=>e.id)}};var Z=class{map=new Map;dispose(){this.map.clear()}emit(e){let i=this.map.get(e.type);if(i)for(let s of[...i])s(e);let r=this.map.get("*");if(r)for(let s of[...r])s(e)}on(e,i){let r=this.map.get(e);return r||(r=new Set,this.map.set(e,r)),r.add(i),()=>{r.delete(i)}}};var Ce={pagination:"paged",pageSize:20,debounceMs:250};var X=class{options;constructor(e){this.options=Object.freeze({...Ce,...e})}};var J=class{filters;map;datasets;primaryDatasetId;store;emitter=new Z;config;debounceTimer=null;debounceResolve=null;queryToken=0;pointsToken=0;constructor(e){this.datasets=e.datasets,this.filters=e.filters??new H,this.map=e.map,this.config=new X(e.config);let i=e.primaryDatasetId??this.datasets.list()[0]?.id;if(i==null||!this.datasets.has(i))throw new Error(`ListingEngine: primary dataset "${i??""}" is not registered \u2014 pass a valid primaryDatasetId or register at least one dataset`);this.primaryDatasetId=i,this.store=new Q({filters:e.initialFilters??{},mode:this.config.options.pagination})}get state(){return this.store.getState()}get options(){return this.config.options}applyFilters(e){this.store.setFilters(e),this.emitter.emit({type:"FiltersChanged",filters:this.currentFilters()}),this.clearDebounce();let i=++this.queryToken,r=this.config.options.debounceMs;return r<=0?this.runQuery(i):new Promise(s=>{this.debounceResolve=s,this.debounceTimer=setTimeout(()=>{this.debounceTimer=null,this.debounceResolve=null,s(this.runQuery(i))},r)})}async loadPage(){let e=this.state.results.nextCursor;if(e===null)return;let i=++this.queryToken,r=this.primaryDataset();this.store.setLoading(!0);try{let s=await r.adapter.list(this.currentFilters(),{cursor:e,limit:this.config.options.pageSize});if(i!==this.queryToken)return;this.config.options.pagination==="infinite"?this.store.appendResults(s):this.store.setResults(s),this.emitter.emit({type:"ResultsLoaded",datasetId:this.primaryDatasetId,count:s.items.length})}finally{i===this.queryToken&&this.store.setLoading(!1)}}async loadPoints(e){this.store.setBounds(e),this.emitter.emit({type:"BoundsChanged",bounds:e});let i=this.currentFilters(),r=++this.pointsToken;await Promise.allSettled(this.datasets.visibleIds().map(async s=>{let o=this.datasets.get(s);if(!o)return;let n=await o.adapter.getPoints(i,e);r===this.pointsToken&&this.store.setPoints(s,n)}))}selectPoint(e,i){this.store.setSelection(i);let r=this.state.points[e]?.find(s=>s.id===i);r&&this.emitter.emit({type:"PointClicked",datasetId:e,id:r.id,entity:r.entity})}setHovered(e,i){this.store.setHovered(i)}toggleLayer(e){let r=!(this.state.layers[e]??!0);this.store.setLayerVisible(e,r),this.emitter.emit({type:"LayerToggled",datasetId:e,visible:r})}subscribe(e){return this.store.subscribe(e)}on(e,i){return this.emitter.on(e,i)}dispose(){this.clearDebounce(),this.emitter.dispose()}async runQuery(e){if(e!==this.queryToken)return;let i=this.primaryDataset();this.store.setLoading(!0);try{let r=await i.adapter.list(this.currentFilters(),{cursor:null,limit:this.config.options.pageSize});if(e!==this.queryToken)return;this.store.setResults(r),this.emitter.emit({type:"ResultsLoaded",datasetId:this.primaryDatasetId,count:r.items.length})}finally{e===this.queryToken&&this.store.setLoading(!1)}}primaryDataset(){return this.datasets.get(this.primaryDatasetId)}currentFilters(){return this.store.getState().filters}clearDebounce(){this.debounceTimer!==null&&(clearTimeout(this.debounceTimer),this.debounceTimer=null),this.debounceResolve!==null&&(this.debounceResolve(),this.debounceResolve=null)}};function Se(...t){let e={config:{},filters:new H,datasets:new G};for(let i of t)i(e);return e}var Ie=t=>e=>{e.config={...e.config,...t}},we=t=>e=>{e.map=t},ke=t=>e=>{e.datasets.add(t)},Ee=t=>e=>{t(e.filters)},yi=t=>e=>{e.urlSync=t},xe=t=>e=>{e.initialFilters=t},vi=t=>e=>{e.primaryDatasetId=t};import{createContext as it,useContext as rt}from"react";import{jsx as S,jsxs as gt}from"react/jsx-runtime";function nt(t){return String(t?.title??"")}var st=({item:t})=>S("div",{children:nt(t)}),ot=()=>S("div",{}),le=()=>S("div",{}),at=({children:t})=>S("div",{children:t}),lt=({children:t})=>S("div",{children:t}),dt=({value:t,onChange:e,placeholder:i})=>S("input",{type:"search",value:t,placeholder:i,onChange:r=>e(r.target.value),"aria-label":i??"Search"}),pt=()=>S("div",{role:"status",children:"No results"}),ct=()=>S("div",{role:"status","aria-busy":"true",children:"Loading\u2026"}),ut=({count:t})=>gt("div",{children:[t," results"]}),mt=({children:t})=>S("div",{children:t}),C={Card:st,Marker:ot,Popup:le,Sidebar:at,FilterPanel:lt,Search:dt,Empty:pt,Loading:ct,ResultHeader:ut,Toolbar:mt},Ne=it(C);function Re(t){let{Card:e,Marker:i,Popup:r,Sidebar:s,FilterPanel:o,Search:n,Empty:a,Loading:d,ResultHeader:l,Toolbar:c,children:h}=t,b={Card:e??C.Card,Marker:i??C.Marker,Popup:r??C.Popup,Sidebar:s??C.Sidebar,FilterPanel:o??C.FilterPanel,Search:n??C.Search,Empty:a??C.Empty,Loading:d??C.Loading,ResultHeader:l??C.ResultHeader,Toolbar:c??C.Toolbar};return S(Ne.Provider,{value:b,children:h})}function P(){return rt(Ne)}import{createContext as ft}from"react";var Y=ft(null);import{useContext as yt}from"react";function g(){let t=yt(Y);if(t===null)throw new Error("useListing must be used within a <ListingProvider>");return t}import{useCallback as Me,useSyncExternalStore as vt}from"react";function I(){let t=g(),e=Me(r=>t.subscribe(r),[t]),i=Me(()=>t.state,[t]);return vt(e,i,i)}import{useCallback as De}from"react";function ee(){let t=g(),e=I(),i=De(s=>t.applyFilters(s),[t]),r=De((s,o)=>t.applyFilters({[s]:o}),[t]);return{filters:e.filters,set:i,setField:r}}import{jsx as $,jsxs as ht}from"react/jsx-runtime";function de({className:t,groupClassName:e,hideLabels:i}={}){let r=g(),{FilterPanel:s}=P(),{filters:o}=ee();return $(s,{children:$("div",{className:t??"space-y-5",children:r.filters.list().map(n=>{if(typeof n.render=="string")return $("div",{"data-filter":n.key,className:e},n.key);let a=n.render;return ht("div",{className:e,children:[n.label&&!i&&$("div",{className:"mb-1.5 text-[13px] font-medium text-foreground",children:n.label}),$(a,{value:n.fromParams(o),onChange:d=>{r.applyFilters(n.toParams(d))}})]},n.key)})})})}function z(){return I().results}import{jsx as te}from"react/jsx-runtime";function Lt(t,e){if(t&&typeof t=="object"&&"id"in t){let i=t.id;if(typeof i=="string"||typeof i=="number")return i}return e}function Oe({className:t}={}){let e=g(),{items:i}=z(),{pagination:r,selection:s}=I(),{Card:o,Empty:n,Loading:a}=P();return r.loading&&i.length===0?te(a,{}):i.length===0?te(n,{}):te("div",{role:"list",className:t,children:i.map((d,l)=>{let c=Lt(d,l);return te(o,{item:d,selected:s===c,onSelect:()=>e.selectPoint(e.primaryDatasetId,c)},c)})})}import{useEffect as W,useRef as B,useState as _e}from"react";import{createPortal as bt}from"react-dom";import{jsx as pe,jsxs as He}from"react/jsx-runtime";var Pt={west:-179.9,south:-85,east:179.9,north:85},Be=.1,Ae=.02;function Tt(t){if(t.length===0)return null;let e=t[0].lng,i=t[0].lng,r=t[0].lat,s=t[0].lat;for(let{lat:a,lng:d}of t)d<e&&(e=d),d>i&&(i=d),a<r&&(r=a),a>s&&(s=a);let o=s>r?(s-r)*Be:Ae,n=i>e?(i-e)*Be:Ae;return{west:e-n,east:i+n,south:r-o,north:s+o}}function ze(t){let{center:e,zoom:i,fallback:r,mapControls:s}=t,o=g(),n=I(),a=B(null),d=B(null),l=B(null),[c,h]=_e(!1),b=B(!1),w=B(!1),k=B(!1),p=o.map;W(()=>{let L=l.current;if(!p||!L)return;let f=[];for(let u of Object.keys(n.points)){if(n.layers[u]===!1)continue;let y=o.datasets.get(u),R=n.points[u]??[],ae={id:u,markers:R.map(M=>({id:M.id,position:M.position,iconUrl:y?.marker.iconUrl?.(M.entity),element:y?.marker.element?.(M.entity)})),clustering:y?.clustering,onMarkerClick:M=>o.selectPoint(u,M)};f.push(p.renderLayer(L,ae))}return()=>{f.forEach(u=>u())}},[o,p,c,n.points,n.layers]),W(()=>{if(!a.current||!p)return;let L=a.current,f=!1,u=null;return(async()=>{let y=await p.mount(L,{center:e,zoom:i,fullscreenTarget:d.current??void 0});if(f){p.destroy(y);return}l.current=y,u=p.onBoundsChange(y,R=>{k.current?k.current=!1:w.current=!0,o.loadPoints(R)}),h(!0),o.loadPoints(Pt)})(),()=>{f=!0,u?.(),l.current&&(p.destroy(l.current),l.current=null),h(!1)}},[o,p]),W(()=>{let L=l.current;if(!p||!L||e||b.current||w.current)return;let f=[];for(let y of Object.keys(n.points))if(n.layers[y]!==!1)for(let R of n.points[y]??[])f.push(R.position);let u=Tt(f);u&&(b.current=!0,k.current=!0,p.fitBounds(L,u))},[p,e,c,n.points,n.layers]),W(()=>{p?.updateMarkerStates(n.selection,n.hovered)},[p,c,n.selection,n.hovered]);let{Popup:F}=P(),O=F!==le,_=n.points[o.primaryDatasetId]??[],A=n.selection!=null?_.find(L=>L.id===n.selection):void 0,[V,j]=_e(null),N=B(A);return N.current=A,W(()=>{let L=l.current;if(!p||!L||!O)return;let f=N.current;if(!f)return;let u=p.mountOverlay(f.position);j({entity:f.entity,position:f.position,container:u.container});let y=()=>o.selectPoint(o.primaryDatasetId,null),R=M=>{M.key==="Escape"&&y()};document.addEventListener("keydown",R);let ae=p.onMapClick(y);return()=>{document.removeEventListener("keydown",R),ae(),u.unmount(),j(null)}},[o,p,c,n.selection,O]),He("div",{ref:d,className:"relative h-full min-h-0 w-full",children:[He("div",{ref:a,className:!p&&r?"flex h-full min-h-0 w-full items-center justify-center":"h-full min-h-0 w-full",children:[!p&&r,O&&V?bt(pe(F,{entity:V.entity,onClose:()=>o.selectPoint(o.primaryDatasetId,null)}),V.container):null]}),s!=null&&pe("div",{className:"pointer-events-none absolute inset-0",children:pe("div",{className:"pointer-events-auto",children:s})})]})}import{jsx as Ft}from"react/jsx-runtime";function Ke(){let t=g(),{results:e,pagination:i}=I();return e.nextCursor==null?null:Ft("button",{type:"button",disabled:i.loading,onClick:()=>{t.loadPage()},children:"Load more"})}import{jsx as Ct}from"react/jsx-runtime";function Ue(){let{items:t,total:e}=z(),{ResultHeader:i}=P();return Ct(i,{count:t.length,total:e})}import{useEffect as St,useRef as It}from"react";function Ve(t,e){let i=g(),r=It(e);r.current=e,St(()=>i.on(t,s=>r.current(s)),[i,t])}import{useEffect as wt,useState as $e}from"react";import{jsx as kt}from"react/jsx-runtime";function We(t){let{children:e,...i}=t,[r]=$e(()=>i),[s,o]=$e(null);return wt(()=>{let n=new J({datasets:r.datasets,filters:r.filters,config:r.config,map:r.map,initialFilters:r.initialFilters,primaryDatasetId:r.primaryDatasetId});return r.urlSync&&r.urlSync.start(n),o(n),()=>{r.urlSync&&r.urlSync.stop(),n.dispose(),o(a=>a===n?null:a)}},[r]),s?kt(Y.Provider,{value:s,children:e}):null}function K(t){return typeof t!="number"?t:new Intl.NumberFormat("en-US",{style:"currency",currency:"USD",maximumFractionDigits:0}).format(t)}import{Fragment as xt,jsx as E,jsxs as qe}from"react/jsx-runtime";function Et(t){return t?"rle-card rle-card--selected":"rle-card"}function ce({item:t,selected:e,onSelect:i}){let r=t??{},s=Et(e),o=qe(xt,{children:[r.imageUrl?E("img",{src:r.imageUrl,alt:r.title??"",className:"rle-card-media"}):E("div",{className:"rle-card-media rle-card-media--placeholder","aria-hidden":"true"}),qe("div",{className:"rle-card-body",children:[r.title&&E("span",{className:"rle-card-title",children:r.title}),r.subtitle&&E("span",{className:"rle-card-address",children:r.subtitle}),r.badge&&E("div",{className:"rle-card-info",children:E("span",{className:"rle-card-info-item",children:r.badge})}),r.price!=null&&E("span",{className:"rle-card-price",children:K(r.price)})]})]});return i?E("button",{type:"button",onClick:i,"aria-pressed":e??!1,className:s,children:o}):E("article",{className:s,children:o})}import{jsx as ie,jsxs as je}from"react/jsx-runtime";function ue(t){return je("div",{role:"status",className:"rle-empty",children:[je("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:1.5,strokeLinecap:"round",strokeLinejoin:"round",className:"rle-empty-icon","aria-hidden":"true",children:[ie("circle",{cx:"11",cy:"11",r:"7"}),ie("path",{d:"m21 21-4.3-4.3"})]}),ie("p",{className:"rle-empty-title",children:"No results"}),ie("p",{className:"rle-empty-hint",children:"Try adjusting your filters or search terms."})]})}import{jsx as Nt}from"react/jsx-runtime";function me({children:t}){return Nt("div",{className:"rle-filter-panel",children:t})}import{jsx as re,jsxs as Rt}from"react/jsx-runtime";function ge(t){return re("div",{className:"rle-loading",role:"status","aria-busy":"true","aria-label":"Loading results",children:Array.from({length:3}).map((e,i)=>Rt("div",{className:"rle-loading-item",children:[re("div",{className:"rle-skeleton",style:{aspectRatio:"4 / 3",width:"100%"}}),re("div",{className:"rle-skeleton",style:{height:16,width:"65%"}}),re("div",{className:"rle-skeleton",style:{height:12,width:"35%"}})]},i))})}import{jsx as Mt}from"react/jsx-runtime";function fe({point:t}){let e=t.entity??{};return Mt("span",{className:"rle-pin",children:e.price!=null?K(e.price):""})}import{jsx as U,jsxs as ye}from"react/jsx-runtime";function ve({entity:t,onClose:e}){let i=t??{};return ye("div",{className:"rle-popup",role:"group","aria-label":"Location details",children:[U("button",{type:"button",onClick:e,"aria-label":"Close",className:"rle-popup-close",children:ye("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round",width:"16",height:"16","aria-hidden":"true",children:[U("path",{d:"M18 6 6 18"}),U("path",{d:"m6 6 12 12"})]})}),ye("div",{children:[i.title&&U("div",{className:"rle-card-title",children:i.title}),i.subtitle&&U("div",{className:"rle-card-address",children:i.subtitle}),i.price!=null&&U("div",{className:"rle-card-price",children:K(i.price)})]})]})}import{jsx as Dt}from"react/jsx-runtime";function he({count:t,total:e}){let i=e!=null&&e!==t?`${t} of ${e} results`:`${t} results`;return Dt("div",{className:"rle-result-header",children:i})}import{jsx as Ot}from"react/jsx-runtime";function Le({value:t,onChange:e,placeholder:i}){return Ot("input",{type:"search",value:t,placeholder:i,onChange:r=>e(r.target.value),"aria-label":i??"Search",className:"rle-input"})}import{jsx as _t}from"react/jsx-runtime";function be({children:t}){return _t("aside",{className:"rle-sidebar",children:t})}import{jsx as Bt}from"react/jsx-runtime";function Pe({children:t}){return Bt("div",{className:"rle-toolbar",children:t})}var Qe={Card:ce,Marker:fe,Popup:ve,Sidebar:be,FilterPanel:me,Search:Le,Empty:ue,Loading:ge,ResultHeader:he,Toolbar:Pe};import{jsx as T,jsxs as q}from"react/jsx-runtime";function Ge({view:t,onViewChange:e}){return T("nav",{className:"rle-bottom-nav","aria-label":"Listing navigation",children:q("div",{className:"rle-viewtoggle",role:"group","aria-label":"View",children:[q("button",{type:"button",className:`rle-viewtoggle__btn${t==="list"?" rle-viewtoggle__btn--active":""}`,"aria-pressed":t==="list",onClick:()=>e("list"),children:[T(At,{}),"List"]}),q("button",{type:"button",className:`rle-viewtoggle__btn${t==="map"?" rle-viewtoggle__btn--active":""}`,"aria-pressed":t==="map",onClick:()=>e("map"),children:[T(Ht,{}),"Map"]})]})})}function At(){return q("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round",width:"16",height:"16","aria-hidden":"true",children:[T("line",{x1:"8",y1:"6",x2:"20",y2:"6"}),T("line",{x1:"8",y1:"12",x2:"20",y2:"12"}),T("line",{x1:"8",y1:"18",x2:"20",y2:"18"}),T("line",{x1:"4",y1:"6",x2:"4.01",y2:"6"}),T("line",{x1:"4",y1:"12",x2:"4.01",y2:"12"}),T("line",{x1:"4",y1:"18",x2:"4.01",y2:"18"})]})}function Ht(){return q("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round",width:"16",height:"16","aria-hidden":"true",children:[T("polygon",{points:"1 6 8 3 16 6 23 3 23 18 16 21 8 18 1 21 1 6"}),T("line",{x1:"8",y1:"3",x2:"8",y2:"18"}),T("line",{x1:"16",y1:"6",x2:"16",y2:"21"})]})}import{useEffect as Te,useRef as zt,useState as Ze}from"react";import{createPortal as Kt}from"react-dom";import{Fragment as Vt,jsx as x,jsxs as ne}from"react/jsx-runtime";function Xe({open:t,onOpenChange:e,title:i,children:r,footer:s}){let o=zt(null),[n,a]=Ze(!1),[d,l]=Ze(!1);return Te(()=>{if(!t){l(!1),a(!1);return}a(!0);let c=requestAnimationFrame(()=>l(!0));return()=>cancelAnimationFrame(c)},[t]),Te(()=>{if(!n)return;let c=document.body.style.overflow;return document.body.style.overflow="hidden",()=>{document.body.style.overflow=c}},[n]),Te(()=>{if(!n)return;o.current?.focus();function c(h){h.key==="Escape"&&e(!1)}return document.addEventListener("keydown",c),()=>document.removeEventListener("keydown",c)},[n,e]),!n||typeof document>"u"?null:Kt(ne(Vt,{children:[x("div",{className:`rle-sheet-backdrop${d?" rle-sheet-backdrop--open":""}`,onClick:()=>e(!1),"aria-hidden":"true"}),ne("div",{ref:o,className:`rle-sheet${d?" rle-sheet--open":""}`,role:"dialog","aria-modal":"true","aria-label":i,tabIndex:-1,children:[x("div",{className:"rle-sheet__handle","aria-hidden":"true"}),ne("div",{className:"rle-sheet__header",children:[i&&x("div",{className:"rle-sheet__title",children:i}),x("button",{type:"button",className:"rle-sheet__close",onClick:()=>e(!1),"aria-label":"Close",children:x(Ut,{})})]}),x("div",{className:"rle-sheet__body",children:r}),s&&x("div",{className:"rle-sheet__footer",children:s})]})]}),document.body)}function Ut(){return ne("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round",width:"16",height:"16","aria-hidden":"true",children:[x("path",{d:"M18 6 6 18"}),x("path",{d:"m6 6 12 12"})]})}import{useEffect as Ye,useRef as qt,useState as oe}from"react";import{jsx as v,jsxs as se}from"react/jsx-runtime";function Je({search:t,onFiltersClick:e,filterCount:i=0,action:r}){let{Search:s}=P();return se("header",{className:"rle-mobile-header",children:[t&&v("div",{className:"rle-mobile-header__search",children:v(s,{value:t.value,onChange:t.onChange,placeholder:t.placeholder})}),se("button",{type:"button",className:"rle-btn rle-mobile-header__btn",onClick:e,children:[v($t,{}),v("span",{children:"Filters"}),i>0&&v("span",{className:"rle-mobile-header__count",children:i})]}),r&&v("button",{type:"button",className:"rle-btn rle-mobile-header__btn rle-mobile-header__btn--icon",onClick:r.onClick,"aria-label":r.label,children:r.icon??v(Wt,{})})]})}function $t(){return se("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:[v("line",{x1:"4",y1:"6",x2:"20",y2:"6"}),v("circle",{cx:"9",cy:"6",r:"2",fill:"currentColor",stroke:"none"}),v("line",{x1:"4",y1:"12",x2:"20",y2:"12"}),v("circle",{cx:"15",cy:"12",r:"2",fill:"currentColor",stroke:"none"}),v("line",{x1:"4",y1:"18",x2:"20",y2:"18"}),v("circle",{cx:"11",cy:"18",r:"2",fill:"currentColor",stroke:"none"})]})}function Wt(){return se("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:[v("line",{x1:"12",y1:"5",x2:"12",y2:"19"}),v("line",{x1:"5",y1:"12",x2:"19",y2:"12"})]})}import{Fragment as Gt,jsx as m,jsxs as D}from"react/jsx-runtime";var jt=m("div",{className:"rle-empty",children:"Map unavailable"});function Qt(){let t=qt(null),[e,i]=oe(!0),[r,s]=oe(!0);return Ye(()=>{let o=t.current;if(!o)return;let n=()=>{let{clientWidth:h,scrollLeft:b,scrollWidth:w}=o;i(b<=0),s(b+h>=w-1)},a=0,d=()=>{a||(a=requestAnimationFrame(()=>{a=0,n()}))};n(),o.addEventListener("scroll",n,{passive:!0});let l,c;return typeof ResizeObserver<"u"&&(l=new ResizeObserver(n),l.observe(o)),typeof MutationObserver<"u"&&(c=new MutationObserver(d),c.observe(o,{characterData:!0,childList:!0,subtree:!0})),()=>{o.removeEventListener("scroll",n),l?.disconnect(),c?.disconnect(),a&&cancelAnimationFrame(a)}},[]),{atEnd:r,atStart:e,ref:t}}function et({search:t,toolbarEnd:e,mobileAction:i,autoFetch:r=!0,hasMap:s,mapCenter:o,mapZoom:n,mapControls:a,className:d}){let l=g(),{Search:c}=P(),h=z(),{filters:b,set:w}=ee(),k=s??l.map!=null,[p,F]=oe("list"),[O,_]=oe(!1),{atEnd:A,atStart:V,ref:j}=Qt(),N=t?{value:String(b[t.filterKey]??""),onChange:y=>{w({[t.filterKey]:y||void 0})},placeholder:t.placeholder}:void 0;Ye(()=>{r!==!1&&l.applyFilters({})},[l,r]);let L=()=>{w(l.filters.clearedParams())},f=l.filters.activeKeys(b).length,u=h.total??h.items.length;return D("div",{className:d?`rle-app ${d}`:"rle-app",children:[D("div",{className:"rle-filter-bar",children:[D("div",{className:"rle-filter-bar__scroll",ref:j,children:[N&&m("div",{className:"rle-filter-bar__search",children:m(c,{value:N.value,onChange:N.onChange,placeholder:N.placeholder})}),m(de,{className:"rle-filters-row",groupClassName:"rle-filter-group",hideLabels:!0})]}),!V&&m("div",{className:"rle-filter-bar__fade rle-filter-bar__fade--start","aria-hidden":"true"}),!A&&m("div",{className:"rle-filter-bar__fade rle-filter-bar__fade--end","aria-hidden":"true"})]}),m(Je,{search:N,onFiltersClick:()=>_(!0),filterCount:f,action:i}),D("div",{className:`rle-body ${k?"rle-split":"rle-body--list-only"}`,"data-mobile-view":p,children:[D("div",{className:"rle-list",children:[D("div",{className:"rle-list-header",children:[m(Ue,{}),e&&m("div",{className:"rle-list-header__toolbar",children:e})]}),m(Oe,{className:"rle-list-grid"}),m(Ke,{})]}),k&&m("div",{className:"rle-map",children:m(ze,{center:o,zoom:n,fallback:jt,mapControls:a})})]}),k&&m(Ge,{view:p,onViewChange:F}),m(Xe,{title:"Filters",open:O,onOpenChange:_,footer:D(Gt,{children:[m("button",{type:"button",className:"rle-btn rle-btn--ghost",onClick:L,children:"Clear all"}),D("button",{type:"button",className:"rle-btn rle-btn--primary",onClick:()=>_(!1),children:["Show ",u," results"]})]}),children:m(de,{className:"rle-filter-stack",groupClassName:"rle-filter-group"})})]})}import{useEffect as Zt,useRef as Xt,useState as Jt}from"react";import{jsx as Fe,jsxs as ti}from"react/jsx-runtime";function tt(t){return"provider"in t}function Yt(t){let e=t!=null&&!tt(t),i=e?t.apiKey:void 0,r=e?t.mapId:void 0,s=e?t.mapOptions:void 0,o=e?t.styles:void 0,[n,a]=Jt(()=>!t||tt(t)?{ready:!0,provider:t?.provider}:{ready:!1});return Zt(()=>{if(!i)return;let d=!1;return import("./maps/google/index.js").then(({googleProvider:l})=>{d||a({ready:!0,provider:l({apiKey:i,mapId:r,mapOptions:s,styles:o})})}),()=>{d=!0}},[i,r]),n}function ei({onFiltersChange:t}){let e=Xt(t);return e.current=t,Ve("FiltersChanged",i=>{i.type==="FiltersChanged"&&e.current(i.filters)}),null}function Pn(t){let{datasets:e,filters:i,map:r,components:s,initialFilters:o,onFiltersChange:n,mobileAction:a,search:d,toolbarEnd:l,mapControls:c,config:h,autoFetch:b,className:w}=t,{ready:k,provider:p}=Yt(r);if(!k)return null;let F=[];for(let A of e)F.push(ke(A));i&&F.push(Ee(i)),p&&F.push(we(p)),o&&F.push(xe(o)),h&&F.push(Ie(h));let O=Se(...F),_={...Qe,...s};return ti(We,{...O,children:[n&&Fe(ei,{onFiltersChange:n}),Fe(Re,{..._,children:Fe(et,{className:w,search:d,toolbarEnd:l,mobileAction:a,autoFetch:b,mapCenter:r?.center,mapZoom:r?.zoom,mapControls:c})})]})}export{Q as a,H as b,G as c,Z as d,Ce as e,X as f,J as g,Se as h,Ie as i,we as j,ke as k,Ee as l,yi as m,xe as n,vi as o,le as p,Re as q,P as r,Y as s,g as t,I as u,ee as v,de as w,z as x,Oe as y,ze as z,Ke as A,Ue as B,Ve as C,We as D,ce as E,ue as F,me as G,ge as H,fe as I,ve as J,he as K,Le as L,be as M,Pe as N,Qe as O,Ge as P,Xe as Q,et as R,Pn as S};
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2;"use client";
2
- var _chunkKJW54NRTcjs = require('./chunk-KJW54NRT.cjs');var m=(e=>(e.Paged="paged",e.Infinite="infinite",e))(m||{});var g=(s=>(s.FiltersChanged="FiltersChanged",s.ResultsLoaded="ResultsLoaded",s.PointClicked="PointClicked",s.BoundsChanged="BoundsChanged",s.LayerToggled="LayerToggled",s))(g||{});var y= (_class =class{__init() {this.listeners=new Set}constructor(t={}){;_class.prototype.__init.call(this);this.query={...t}}getQuery(){return{...this.query}}setQuery(t){this.query={...t},this.notify()}subscribe(t){return this.listeners.add(t),()=>{this.listeners.delete(t)}}notify(){for(let t of[...this.listeners])t()}}, _class);function P(r,t){let e=new Set([...Object.keys(r),...Object.keys(t)]);for(let i of e)if(r[i]!==t[i])return!1;return!0}var c= (_class2 =class{__init2() {this.isSyncing=!1}__init3() {this.unsubscribeEngine=null}__init4() {this.unsubscribeHistory=null}constructor(t){;_class2.prototype.__init2.call(this);_class2.prototype.__init3.call(this);_class2.prototype.__init4.call(this);this.history=t.history,this.toQueryFn=t.toQuery,this.toFiltersFn=t.toFilters,this.hydrateOnStart=_nullishCoalesce(t.hydrateOnStart, () => (!0))}start(t){this.stop(),this.unsubscribeEngine=t.subscribe(()=>{this.isSyncing||this.syncEngineToHistory(t)}),this.unsubscribeHistory=this.history.subscribe(()=>{this.isSyncing||this.withSyncGuard(()=>{this.applyFiltersSafely(t,this.toFiltersFn(this.history.getQuery()))})}),this.hydrateOnStart&&this.withSyncGuard(()=>{this.applyFiltersSafely(t,this.toFiltersFn(this.history.getQuery()))})}stop(){_optionalChain([this, 'access', _ => _.unsubscribeEngine, 'optionalCall', _2 => _2()]),this.unsubscribeEngine=null,_optionalChain([this, 'access', _3 => _3.unsubscribeHistory, 'optionalCall', _4 => _4()]),this.unsubscribeHistory=null}syncEngineToHistory(t){let e=this.toQueryFn(t.state.filters);P(e,this.history.getQuery())||this.withSyncGuard(()=>this.history.setQuery(e))}applyFiltersSafely(t,e){Promise.resolve(t.applyFilters(e)).catch(()=>{})}withSyncGuard(t){this.isSyncing=!0;try{t()}finally{this.isSyncing=!1}}}, _class2);var p=class{constructor(t={}){this.mode=_nullishCoalesce(t.mode, () => ("replace"))}getQuery(){if(typeof window>"u")return{};let t=new URLSearchParams(window.location.search),e={};for(let[i,o]of t)o!==""&&(e[i]=o);return e}setQuery(t){if(typeof window>"u")return;let e=new URLSearchParams;for(let[h,u]of Object.entries(t))u===void 0||u===""||e.set(h,u);let i=e.toString(),o=i?`?${i}`:"";if(o===window.location.search)return;let s=`${window.location.pathname}${o}${window.location.hash}`;this.mode==="push"?window.history.pushState(window.history.state,"",s):window.history.replaceState(window.history.state,"",s)}subscribe(t){return typeof window>"u"?()=>{}:(window.addEventListener("popstate",t),()=>{window.removeEventListener("popstate",t)})}};var _jsxruntime = require('react/jsx-runtime');function M({children:r}){let{Toolbar:t}=_chunkKJW54NRTcjs.q.call(void 0, );return _jsxruntime.jsx.call(void 0, t,{children:r})}var _react = require('react');function ot(){let r=_chunkKJW54NRTcjs.s.call(void 0, ),t=_chunkKJW54NRTcjs.t.call(void 0, ),e=_react.useCallback.call(void 0, o=>r.loadPoints(o),[r]),i=_react.useCallback.call(void 0, (o,s)=>r.selectPoint(o,s),[r]);return{bounds:t.bounds,points:t.points,loadPoints:e,selectPoint:i}}function yt(r){let t=_chunkKJW54NRTcjs.s.call(void 0, ),e=_chunkKJW54NRTcjs.t.call(void 0, ),i=_react.useCallback.call(void 0, ()=>t.toggleLayer(r),[t,r]);return{visible:_nullishCoalesce(e.layers[r], () => (!0)),points:_nullishCoalesce(e.points[r], () => ([])),toggle:i}}exports.BrowserHistoryPort = p; exports.DatasetRegistry = _chunkKJW54NRTcjs.c; exports.FilterRegistry = _chunkKJW54NRTcjs.b; exports.ListingApp = _chunkKJW54NRTcjs.R; exports.ListingComponentsProvider = _chunkKJW54NRTcjs.p; exports.ListingConfig = _chunkKJW54NRTcjs.f; exports.ListingEngine = _chunkKJW54NRTcjs.g; exports.ListingEngineContext = _chunkKJW54NRTcjs.r; exports.ListingEventType = g; exports.ListingFilters = _chunkKJW54NRTcjs.v; exports.ListingList = _chunkKJW54NRTcjs.x; exports.ListingMap = _chunkKJW54NRTcjs.y; exports.ListingPagination = _chunkKJW54NRTcjs.z; exports.ListingProvider = _chunkKJW54NRTcjs.C; exports.ListingResultHeader = _chunkKJW54NRTcjs.A; exports.ListingStore = _chunkKJW54NRTcjs.a; exports.ListingToolbar = M; exports.MemoryHistoryPort = y; exports.PaginationMode = m; exports.TypedEmitter = _chunkKJW54NRTcjs.d; exports.UrlSyncController = c; exports.composeListingProviders = _chunkKJW54NRTcjs.h; exports.listingDefaultConfig = _chunkKJW54NRTcjs.e; exports.useListing = _chunkKJW54NRTcjs.s; exports.useListingComponents = _chunkKJW54NRTcjs.q; exports.useListingEvent = _chunkKJW54NRTcjs.B; exports.useListingFilters = _chunkKJW54NRTcjs.u; exports.useListingLayer = yt; exports.useListingMap = ot; exports.useListingResults = _chunkKJW54NRTcjs.w; exports.useListingState = _chunkKJW54NRTcjs.t; exports.withConfig = _chunkKJW54NRTcjs.i; exports.withDataset = _chunkKJW54NRTcjs.k; exports.withFilters = _chunkKJW54NRTcjs.l; exports.withInitialFilters = _chunkKJW54NRTcjs.n; exports.withMap = _chunkKJW54NRTcjs.j; exports.withPrimaryDataset = _chunkKJW54NRTcjs.o; exports.withUrlSync = _chunkKJW54NRTcjs.m;
2
+ var _chunk6HHIXJWEcjs = require('./chunk-6HHIXJWE.cjs');var P=(r=>(r.Paged="paged",r.Infinite="infinite",r))(P||{});var v=(i=>(i.FiltersChanged="FiltersChanged",i.ResultsLoaded="ResultsLoaded",i.PointClicked="PointClicked",i.BoundsChanged="BoundsChanged",i.LayerToggled="LayerToggled",i))(v||{});var d= (_class =class{__init() {this.listeners=new Set}constructor(t={}){;_class.prototype.__init.call(this);this.query={...t}}getQuery(){return{...this.query}}setQuery(t){this.query={...t},this.notify()}subscribe(t){return this.listeners.add(t),()=>{this.listeners.delete(t)}}notify(){for(let t of[...this.listeners])t()}}, _class);function b(e,t){let r=new Set([...Object.keys(e),...Object.keys(t)]);for(let s of r)if(e[s]!==t[s])return!1;return!0}var h= (_class2 =class{__init2() {this.isSyncing=!1}__init3() {this.unsubscribeEngine=null}__init4() {this.unsubscribeHistory=null}constructor(t){;_class2.prototype.__init2.call(this);_class2.prototype.__init3.call(this);_class2.prototype.__init4.call(this);this.history=t.history,this.toQueryFn=t.toQuery,this.toFiltersFn=t.toFilters,this.hydrateOnStart=_nullishCoalesce(t.hydrateOnStart, () => (!0))}start(t){this.stop(),this.unsubscribeEngine=t.subscribe(()=>{this.isSyncing||this.syncEngineToHistory(t)}),this.unsubscribeHistory=this.history.subscribe(()=>{this.isSyncing||this.withSyncGuard(()=>{this.applyFiltersSafely(t,this.toFiltersFn(this.history.getQuery()))})}),this.hydrateOnStart&&this.withSyncGuard(()=>{this.applyFiltersSafely(t,this.toFiltersFn(this.history.getQuery()))})}stop(){_optionalChain([this, 'access', _ => _.unsubscribeEngine, 'optionalCall', _2 => _2()]),this.unsubscribeEngine=null,_optionalChain([this, 'access', _3 => _3.unsubscribeHistory, 'optionalCall', _4 => _4()]),this.unsubscribeHistory=null}syncEngineToHistory(t){let r=this.toQueryFn(t.state.filters);b(r,this.history.getQuery())||this.withSyncGuard(()=>this.history.setQuery(r))}applyFiltersSafely(t,r){Promise.resolve(t.applyFilters(r)).catch(()=>{})}withSyncGuard(t){this.isSyncing=!0;try{t()}finally{this.isSyncing=!1}}}, _class2);var m=class{constructor(t={}){this.mode=_nullishCoalesce(t.mode, () => ("replace"))}getQuery(){if(typeof window>"u")return{};let t=new URLSearchParams(window.location.search),r={};for(let[s,o]of t)o!==""&&(r[s]=o);return r}setQuery(t){if(typeof window>"u")return;let r=new URLSearchParams;for(let[c,a]of Object.entries(t))a===void 0||a===""||r.set(c,a);let s=r.toString(),o=s?`?${s}`:"";if(o===window.location.search)return;let i=`${window.location.pathname}${o}${window.location.hash}`;this.mode==="push"?window.history.pushState(window.history.state,"",i):window.history.replaceState(window.history.state,"",i)}subscribe(t){return typeof window>"u"?()=>{}:(window.addEventListener("popstate",t),()=>{window.removeEventListener("popstate",t)})}};var _jsxruntime = require('react/jsx-runtime');function rt({children:e}){let{Toolbar:t}=_chunk6HHIXJWEcjs.r.call(void 0, );return _jsxruntime.jsx.call(void 0, t,{children:e})}var _react = require('react');function lt(){let e=_chunk6HHIXJWEcjs.t.call(void 0, ),t=_chunk6HHIXJWEcjs.u.call(void 0, ),r=_react.useCallback.call(void 0, l=>e.loadPoints(l),[e]),s=_react.useCallback.call(void 0, (l,f)=>e.selectPoint(l,f),[e]),o=_react.useCallback.call(void 0, l=>e.setHovered(e.primaryDatasetId,l),[e]),i=_react.useCallback.call(void 0, ()=>_optionalChain([e, 'access', _5 => _5.map, 'optionalAccess', _6 => _6.zoomIn, 'call', _7 => _7()]),[e]),c=_react.useCallback.call(void 0, ()=>_optionalChain([e, 'access', _8 => _8.map, 'optionalAccess', _9 => _9.zoomOut, 'call', _10 => _10()]),[e]),a=_react.useCallback.call(void 0, ()=>_optionalChain([e, 'access', _11 => _11.map, 'optionalAccess', _12 => _12.toggleFullscreen, 'call', _13 => _13()]),[e]);return{bounds:t.bounds,points:t.points,hovered:t.hovered,loadPoints:r,selectPoint:s,setHovered:o,zoomIn:i,zoomOut:c,toggleFullscreen:a}}function dt(e){let t=_chunk6HHIXJWEcjs.t.call(void 0, ),r=_chunk6HHIXJWEcjs.u.call(void 0, ),s=_react.useCallback.call(void 0, ()=>t.toggleLayer(e),[t,e]);return{visible:_nullishCoalesce(r.layers[e], () => (!0)),points:_nullishCoalesce(r.points[e], () => ([])),toggle:s}}exports.BrowserHistoryPort = m; exports.DatasetRegistry = _chunk6HHIXJWEcjs.c; exports.FallbackPopup = _chunk6HHIXJWEcjs.p; exports.FilterRegistry = _chunk6HHIXJWEcjs.b; exports.ListingApp = _chunk6HHIXJWEcjs.S; exports.ListingComponentsProvider = _chunk6HHIXJWEcjs.q; exports.ListingConfig = _chunk6HHIXJWEcjs.f; exports.ListingEngine = _chunk6HHIXJWEcjs.g; exports.ListingEngineContext = _chunk6HHIXJWEcjs.s; exports.ListingEventType = v; exports.ListingFilters = _chunk6HHIXJWEcjs.w; exports.ListingList = _chunk6HHIXJWEcjs.y; exports.ListingMap = _chunk6HHIXJWEcjs.z; exports.ListingPagination = _chunk6HHIXJWEcjs.A; exports.ListingProvider = _chunk6HHIXJWEcjs.D; exports.ListingResultHeader = _chunk6HHIXJWEcjs.B; exports.ListingStore = _chunk6HHIXJWEcjs.a; exports.ListingToolbar = rt; exports.MemoryHistoryPort = d; exports.PaginationMode = P; exports.TypedEmitter = _chunk6HHIXJWEcjs.d; exports.UrlSyncController = h; exports.composeListingProviders = _chunk6HHIXJWEcjs.h; exports.listingDefaultConfig = _chunk6HHIXJWEcjs.e; exports.useListing = _chunk6HHIXJWEcjs.t; exports.useListingComponents = _chunk6HHIXJWEcjs.r; exports.useListingEvent = _chunk6HHIXJWEcjs.C; exports.useListingFilters = _chunk6HHIXJWEcjs.v; exports.useListingLayer = dt; exports.useListingMap = lt; exports.useListingResults = _chunk6HHIXJWEcjs.x; exports.useListingState = _chunk6HHIXJWEcjs.u; exports.withConfig = _chunk6HHIXJWEcjs.i; exports.withDataset = _chunk6HHIXJWEcjs.k; exports.withFilters = _chunk6HHIXJWEcjs.l; exports.withInitialFilters = _chunk6HHIXJWEcjs.n; exports.withMap = _chunk6HHIXJWEcjs.j; exports.withPrimaryDataset = _chunk6HHIXJWEcjs.o; exports.withUrlSync = _chunk6HHIXJWEcjs.m;
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
- import { P as Page, B as Bounds, E as EntityId, M as MapPoint, U as Unsubscribe, a as MapProvider, Q as QueryParams, L as LatLng } from './map-provider.interface-DT-v1plm.cjs';
2
- export { b as EntityAdapter, c as MapHandle, d as MapInitOptions, e as PageRequest, R as RenderedLayer } from './map-provider.interface-DT-v1plm.cjs';
3
- import { P as PaginationMode, D as DatasetDefinition, I as IListingConfigOptions, F as FilterRegistry, a as IListingToolbarProps } from './listing-app-CtF5E1ja.cjs';
4
- export { C as ClusterOptions, b as FilterControlProps, c as FilterDefinition, d as IListingCardProps, e as IListingComponents, f as IListingEmptyProps, g as IListingFilterPanelProps, h as IListingLoadingProps, i as IListingMarkerProps, j as IListingPopupProps, k as IListingResultHeaderProps, l as IListingSearchProps, m as IListingSidebarProps, L as ListingApp, n as ListingAppProps, o as ListingComponentsProvider, M as MarkerRenderer, u as useListingComponents } from './listing-app-CtF5E1ja.cjs';
1
+ import { P as Page, B as Bounds, E as EntityId, M as MapPoint, U as Unsubscribe, a as MapProvider, Q as QueryParams, L as LatLng } from './map-provider.interface-B5Law7gE.cjs';
2
+ export { b as EntityAdapter, c as MapHandle, d as MapInitOptions, e as MapOverlayHandle, f as PageRequest, R as RenderedLayer } from './map-provider.interface-B5Law7gE.cjs';
3
+ import { P as PaginationMode, D as DatasetDefinition, I as IListingConfigOptions, F as FilterRegistry, a as IListingToolbarProps } from './listing-app-C7EeHlmP.cjs';
4
+ export { C as ClusterOptions, b as FallbackPopup, c as FilterControlProps, d as FilterDefinition, e as IListingCardProps, f as IListingComponents, g as IListingEmptyProps, h as IListingFilterPanelProps, i as IListingLoadingProps, j as IListingMarkerProps, k as IListingPopupProps, l as IListingResultHeaderProps, m as IListingSearchProps, n as IListingSidebarProps, L as ListingApp, o as ListingAppProps, p as ListingComponentsProvider, M as MarkerRenderer, u as useListingComponents } from './listing-app-C7EeHlmP.cjs';
5
5
  import * as react from 'react';
6
6
  import { ReactNode } from 'react';
7
7
 
@@ -18,6 +18,7 @@ interface ListingState<TEntity, TFilters> {
18
18
  results: Page<TEntity>;
19
19
  bounds: Bounds | null;
20
20
  selection: EntityId | null;
21
+ hovered: EntityId | null;
21
22
  pagination: {
22
23
  mode: PaginationMode;
23
24
  loading: boolean;
@@ -43,6 +44,7 @@ declare class ListingStore<TEntity, TFilters> {
43
44
  appendResults(page: Page<TEntity>): void;
44
45
  setBounds(bounds: Bounds | null): void;
45
46
  setSelection(id: EntityId | null): void;
47
+ setHovered(id: EntityId | null): void;
46
48
  setLayerVisible(id: string, visible: boolean): void;
47
49
  setLoading(loading: boolean): void;
48
50
  setPoints(datasetId: string, points: MapPoint<unknown>[]): void;
@@ -177,6 +179,7 @@ declare class ListingEngine<TEntity, TFilters> {
177
179
  readonly north: number;
178
180
  } | null;
179
181
  readonly selection: EntityId | null;
182
+ readonly hovered: EntityId | null;
180
183
  readonly pagination: {
181
184
  readonly mode: PaginationMode;
182
185
  readonly loading: boolean;
@@ -199,7 +202,8 @@ declare class ListingEngine<TEntity, TFilters> {
199
202
  applyFilters(patch: Partial<TFilters>): Promise<void>;
200
203
  loadPage(): Promise<void>;
201
204
  loadPoints(bounds: Bounds): Promise<void>;
202
- selectPoint(datasetId: string, id: EntityId): void;
205
+ selectPoint(datasetId: string, id: EntityId | null): void;
206
+ setHovered(_datasetId: string, id: EntityId | null): void;
203
207
  toggleLayer(id: string): void;
204
208
  subscribe(cb: () => void): () => void;
205
209
  on(type: ListingEvent<TEntity, TFilters>['type'] | '*', cb: (e: ListingEvent<TEntity, TFilters>) => void): () => void;
@@ -460,6 +464,17 @@ interface IListingMapProps {
460
464
  * for the provider to mount into.
461
465
  */
462
466
  fallback?: ReactNode;
467
+ /**
468
+ * Rendered as an absolutely-positioned overlay floating over the map (e.g. zoom/fullscreen
469
+ * buttons), independent of `MapProvider.mount`/the map SDK -- unlike the `Popup` slot (which is
470
+ * portaled through `provider.mountOverlay` so it can be lat/lng-anchored and pan with the map),
471
+ * this is a plain React child laid over the WHOLE map area, positioned by the consumer's own
472
+ * CSS on `mapControls`' content (e.g. `top-right`). The overlay wrapper itself is
473
+ * `pointer-events: none` (so it never blocks map drag/click-through) while `mapControls` is
474
+ * wrapped in a `pointer-events: auto` node so its own interactive content stays clickable.
475
+ * Omit (the default, `undefined`) to render nothing extra -- no behavior change.
476
+ */
477
+ mapControls?: ReactNode;
463
478
  }
464
479
  /**
465
480
  * Structure-only map mount point.
@@ -475,8 +490,9 @@ interface IListingMapProps {
475
490
  * `ListingEngine.datasets` in the task report). Each marker's click routes
476
491
  * to `engine.selectPoint(datasetId, markerId)`.
477
492
  * - Mount effect (declared SECOND): awaits `provider.mount(container, {
478
- * center, zoom })`, stashes the resulting `MapHandle` in a ref, and wires
479
- * `provider.onBoundsChange(handle, b => engine.loadPoints(b))`. Cleanup
493
+ * center, zoom, fullscreenTarget })`, stashes the resulting `MapHandle` in a ref, and wires
494
+ * `provider.onBoundsChange(handle, b => engine.loadPoints(b))`. `fullscreenTarget` is the outer
495
+ * wrapper (`wrapperRef`), not `container` itself -- see "`mapControls`" below for why. Cleanup
480
496
  * unsubscribes bounds and calls `provider.destroy(handle)`. Also kicks a
481
497
  * one-time, unbounded `engine.loadPoints(WORLD_BOUNDS)` right after the
482
498
  * handle is ready -- see "Auto-fit" below for why.
@@ -547,17 +563,50 @@ interface IListingMapProps {
547
563
  * subscription registered in the first place) instead of leaking a live map
548
564
  * instance that nothing in the component tree references anymore.
549
565
  *
550
- * Deliberately out of scope for this task (documented future enhancements):
551
- * rendering the injected `Marker`/`Popup` React components INTO map markers
552
- * via portals -- only `iconUrl` + `onMarkerClick` -> `selectPoint` is wired;
553
- * and rendering the injected `Popup` for `state.selection` as an overlay
554
- * beside the map.
566
+ * Popup overlay: when a `Popup` slot is injected (via `ListingComponentsProvider`)
567
+ * AND `state.selection` resolves to a loaded point of the primary dataset, the
568
+ * injected `Popup` is rendered -- via `createPortal` -- into an on-map overlay
569
+ * anchored at that point (`provider.mountOverlay(point.position)`; see that
570
+ * method's doc comment for the sync-container / async-attach split). The
571
+ * selected entity + anchor position are CAPTURED into component state
572
+ * (`capturedPopup`) when the overlay mounts, and the rendered `Popup` reads from
573
+ * that snapshot rather than from the live, pan-reactive `selected` -- so a pan
574
+ * that drops the selected point out of `state.points` leaves the open popup
575
+ * anchored and intact (it pans with the map like a Google InfoWindow) instead
576
+ * of tearing its content out and leaving an empty overlay behind. The popup is
577
+ * dismissed -- clearing the capture, unmounting the overlay, and clearing the
578
+ * selection via `engine.selectPoint(primary, null)` -- by the `Popup`'s own
579
+ * `onClose`, the `Esc` key, or a click on the map BACKGROUND
580
+ * (`provider.onMapClick`; marker clicks live in a separate pane and never fire
581
+ * it). Fully backward compatible: with NO `Popup` slot provided, nothing is
582
+ * mounted and there is no behavior change (detected by `Popup !== FallbackPopup`
583
+ * reference identity).
584
+ *
585
+ * Deliberately out of scope for this task (documented future enhancement):
586
+ * rendering the injected `Marker` React component INTO map markers via portals
587
+ * (only `iconUrl` + `onMarkerClick` -> `selectPoint` is wired).
555
588
  *
556
589
  * `fallback`: when `engine.map` is `undefined` (no `MapProvider` configured),
557
590
  * `fallback` renders centered inside the same ref'd container instead of an
558
591
  * empty div. The mount/layer effects both already no-op without a `provider`
559
592
  * (see their guards below), so swapping in `fallback` content here is purely
560
593
  * a render-output change -- it does not touch the mount lifecycle.
594
+ *
595
+ * `mapControls`: rendered as a plain (non-portaled) React overlay laid over the WHOLE map area --
596
+ * see `IListingMapProps.mapControls`'s own doc comment. Deliberately NOT a child of the ref'd
597
+ * container passed to `provider.mount()`: a real map SDK (e.g. Google Maps) takes ownership of
598
+ * that element's contents, so `mapControls` is instead a sibling inside an outer wrapper `<div>`
599
+ * (`wrapperRef`), absolutely positioned over it via CSS -- never competing with the map SDK for
600
+ * that node's children. `null`/`undefined` renders nothing extra (no wrapper divs at all), so
601
+ * this is a fully backward-compatible addition.
602
+ *
603
+ * Because `mapControls` is a SIBLING of the map mount div rather than a descendant, a
604
+ * fullscreen/zoom button rendered through it needs `toggleFullscreen()` to target an element that
605
+ * CONTAINS both of them -- the Fullscreen API only shows the target element and its descendants,
606
+ * so fullscreening the mount div alone would make any such button disappear the instant
607
+ * fullscreen is entered. `wrapperRef` (the outer `<div>` itself) is passed as `fullscreenTarget`
608
+ * in the mount effect above for exactly this reason -- see `MapInitOptions.fullscreenTarget`'s
609
+ * doc comment.
561
610
  */
562
611
  declare function ListingMap(props: IListingMapProps): react.JSX.Element;
563
612
 
@@ -646,6 +695,7 @@ declare function useListingState<TEntity = unknown, TFilters = unknown>(): {
646
695
  readonly north: number;
647
696
  } | null;
648
697
  readonly selection: EntityId | null;
698
+ readonly hovered: EntityId | null;
649
699
  readonly pagination: {
650
700
  readonly mode: PaginationMode;
651
701
  readonly loading: boolean;
@@ -687,7 +737,12 @@ declare function useListingFilters<TFilters = unknown>(): {
687
737
  setField: <K_2 extends keyof TFilters>(key: K_2, value: TFilters[K_2]) => Promise<void>;
688
738
  };
689
739
 
690
- /** Map-facing slice of listing state (bounds, per-dataset points) plus the two engine actions that drive them. */
740
+ /**
741
+ * Map-facing slice of listing state (bounds, per-dataset points, hovered
742
+ * marker id) plus the engine actions that drive them. `hovered` is bound to
743
+ * the primary dataset (`engine.primaryDatasetId`) -- a transient
744
+ * highlight-on-hover affordance, independent of `selectPoint`'s `selection`.
745
+ */
691
746
  declare function useListingMap(): {
692
747
  bounds: {
693
748
  readonly west: number;
@@ -705,8 +760,13 @@ declare function useListingMap(): {
705
760
  readonly entity: unknown;
706
761
  }[];
707
762
  };
763
+ hovered: EntityId | null;
708
764
  loadPoints: (bounds: Bounds) => Promise<void>;
709
- selectPoint: (datasetId: string, id: EntityId) => void;
765
+ selectPoint: (datasetId: string, id: EntityId | null) => void;
766
+ setHovered: (id: EntityId | null) => void;
767
+ zoomIn: () => void | undefined;
768
+ zoomOut: () => void | undefined;
769
+ toggleFullscreen: () => void | undefined;
710
770
  };
711
771
 
712
772
  /**
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { P as Page, B as Bounds, E as EntityId, M as MapPoint, U as Unsubscribe, a as MapProvider, Q as QueryParams, L as LatLng } from './map-provider.interface-DT-v1plm.js';
2
- export { b as EntityAdapter, c as MapHandle, d as MapInitOptions, e as PageRequest, R as RenderedLayer } from './map-provider.interface-DT-v1plm.js';
3
- import { P as PaginationMode, D as DatasetDefinition, I as IListingConfigOptions, F as FilterRegistry, a as IListingToolbarProps } from './listing-app-BeYPcPVw.js';
4
- export { C as ClusterOptions, b as FilterControlProps, c as FilterDefinition, d as IListingCardProps, e as IListingComponents, f as IListingEmptyProps, g as IListingFilterPanelProps, h as IListingLoadingProps, i as IListingMarkerProps, j as IListingPopupProps, k as IListingResultHeaderProps, l as IListingSearchProps, m as IListingSidebarProps, L as ListingApp, n as ListingAppProps, o as ListingComponentsProvider, M as MarkerRenderer, u as useListingComponents } from './listing-app-BeYPcPVw.js';
1
+ import { P as Page, B as Bounds, E as EntityId, M as MapPoint, U as Unsubscribe, a as MapProvider, Q as QueryParams, L as LatLng } from './map-provider.interface-B5Law7gE.js';
2
+ export { b as EntityAdapter, c as MapHandle, d as MapInitOptions, e as MapOverlayHandle, f as PageRequest, R as RenderedLayer } from './map-provider.interface-B5Law7gE.js';
3
+ import { P as PaginationMode, D as DatasetDefinition, I as IListingConfigOptions, F as FilterRegistry, a as IListingToolbarProps } from './listing-app-DHFJtnKI.js';
4
+ export { C as ClusterOptions, b as FallbackPopup, c as FilterControlProps, d as FilterDefinition, e as IListingCardProps, f as IListingComponents, g as IListingEmptyProps, h as IListingFilterPanelProps, i as IListingLoadingProps, j as IListingMarkerProps, k as IListingPopupProps, l as IListingResultHeaderProps, m as IListingSearchProps, n as IListingSidebarProps, L as ListingApp, o as ListingAppProps, p as ListingComponentsProvider, M as MarkerRenderer, u as useListingComponents } from './listing-app-DHFJtnKI.js';
5
5
  import * as react from 'react';
6
6
  import { ReactNode } from 'react';
7
7
 
@@ -18,6 +18,7 @@ interface ListingState<TEntity, TFilters> {
18
18
  results: Page<TEntity>;
19
19
  bounds: Bounds | null;
20
20
  selection: EntityId | null;
21
+ hovered: EntityId | null;
21
22
  pagination: {
22
23
  mode: PaginationMode;
23
24
  loading: boolean;
@@ -43,6 +44,7 @@ declare class ListingStore<TEntity, TFilters> {
43
44
  appendResults(page: Page<TEntity>): void;
44
45
  setBounds(bounds: Bounds | null): void;
45
46
  setSelection(id: EntityId | null): void;
47
+ setHovered(id: EntityId | null): void;
46
48
  setLayerVisible(id: string, visible: boolean): void;
47
49
  setLoading(loading: boolean): void;
48
50
  setPoints(datasetId: string, points: MapPoint<unknown>[]): void;
@@ -177,6 +179,7 @@ declare class ListingEngine<TEntity, TFilters> {
177
179
  readonly north: number;
178
180
  } | null;
179
181
  readonly selection: EntityId | null;
182
+ readonly hovered: EntityId | null;
180
183
  readonly pagination: {
181
184
  readonly mode: PaginationMode;
182
185
  readonly loading: boolean;
@@ -199,7 +202,8 @@ declare class ListingEngine<TEntity, TFilters> {
199
202
  applyFilters(patch: Partial<TFilters>): Promise<void>;
200
203
  loadPage(): Promise<void>;
201
204
  loadPoints(bounds: Bounds): Promise<void>;
202
- selectPoint(datasetId: string, id: EntityId): void;
205
+ selectPoint(datasetId: string, id: EntityId | null): void;
206
+ setHovered(_datasetId: string, id: EntityId | null): void;
203
207
  toggleLayer(id: string): void;
204
208
  subscribe(cb: () => void): () => void;
205
209
  on(type: ListingEvent<TEntity, TFilters>['type'] | '*', cb: (e: ListingEvent<TEntity, TFilters>) => void): () => void;
@@ -460,6 +464,17 @@ interface IListingMapProps {
460
464
  * for the provider to mount into.
461
465
  */
462
466
  fallback?: ReactNode;
467
+ /**
468
+ * Rendered as an absolutely-positioned overlay floating over the map (e.g. zoom/fullscreen
469
+ * buttons), independent of `MapProvider.mount`/the map SDK -- unlike the `Popup` slot (which is
470
+ * portaled through `provider.mountOverlay` so it can be lat/lng-anchored and pan with the map),
471
+ * this is a plain React child laid over the WHOLE map area, positioned by the consumer's own
472
+ * CSS on `mapControls`' content (e.g. `top-right`). The overlay wrapper itself is
473
+ * `pointer-events: none` (so it never blocks map drag/click-through) while `mapControls` is
474
+ * wrapped in a `pointer-events: auto` node so its own interactive content stays clickable.
475
+ * Omit (the default, `undefined`) to render nothing extra -- no behavior change.
476
+ */
477
+ mapControls?: ReactNode;
463
478
  }
464
479
  /**
465
480
  * Structure-only map mount point.
@@ -475,8 +490,9 @@ interface IListingMapProps {
475
490
  * `ListingEngine.datasets` in the task report). Each marker's click routes
476
491
  * to `engine.selectPoint(datasetId, markerId)`.
477
492
  * - Mount effect (declared SECOND): awaits `provider.mount(container, {
478
- * center, zoom })`, stashes the resulting `MapHandle` in a ref, and wires
479
- * `provider.onBoundsChange(handle, b => engine.loadPoints(b))`. Cleanup
493
+ * center, zoom, fullscreenTarget })`, stashes the resulting `MapHandle` in a ref, and wires
494
+ * `provider.onBoundsChange(handle, b => engine.loadPoints(b))`. `fullscreenTarget` is the outer
495
+ * wrapper (`wrapperRef`), not `container` itself -- see "`mapControls`" below for why. Cleanup
480
496
  * unsubscribes bounds and calls `provider.destroy(handle)`. Also kicks a
481
497
  * one-time, unbounded `engine.loadPoints(WORLD_BOUNDS)` right after the
482
498
  * handle is ready -- see "Auto-fit" below for why.
@@ -547,17 +563,50 @@ interface IListingMapProps {
547
563
  * subscription registered in the first place) instead of leaking a live map
548
564
  * instance that nothing in the component tree references anymore.
549
565
  *
550
- * Deliberately out of scope for this task (documented future enhancements):
551
- * rendering the injected `Marker`/`Popup` React components INTO map markers
552
- * via portals -- only `iconUrl` + `onMarkerClick` -> `selectPoint` is wired;
553
- * and rendering the injected `Popup` for `state.selection` as an overlay
554
- * beside the map.
566
+ * Popup overlay: when a `Popup` slot is injected (via `ListingComponentsProvider`)
567
+ * AND `state.selection` resolves to a loaded point of the primary dataset, the
568
+ * injected `Popup` is rendered -- via `createPortal` -- into an on-map overlay
569
+ * anchored at that point (`provider.mountOverlay(point.position)`; see that
570
+ * method's doc comment for the sync-container / async-attach split). The
571
+ * selected entity + anchor position are CAPTURED into component state
572
+ * (`capturedPopup`) when the overlay mounts, and the rendered `Popup` reads from
573
+ * that snapshot rather than from the live, pan-reactive `selected` -- so a pan
574
+ * that drops the selected point out of `state.points` leaves the open popup
575
+ * anchored and intact (it pans with the map like a Google InfoWindow) instead
576
+ * of tearing its content out and leaving an empty overlay behind. The popup is
577
+ * dismissed -- clearing the capture, unmounting the overlay, and clearing the
578
+ * selection via `engine.selectPoint(primary, null)` -- by the `Popup`'s own
579
+ * `onClose`, the `Esc` key, or a click on the map BACKGROUND
580
+ * (`provider.onMapClick`; marker clicks live in a separate pane and never fire
581
+ * it). Fully backward compatible: with NO `Popup` slot provided, nothing is
582
+ * mounted and there is no behavior change (detected by `Popup !== FallbackPopup`
583
+ * reference identity).
584
+ *
585
+ * Deliberately out of scope for this task (documented future enhancement):
586
+ * rendering the injected `Marker` React component INTO map markers via portals
587
+ * (only `iconUrl` + `onMarkerClick` -> `selectPoint` is wired).
555
588
  *
556
589
  * `fallback`: when `engine.map` is `undefined` (no `MapProvider` configured),
557
590
  * `fallback` renders centered inside the same ref'd container instead of an
558
591
  * empty div. The mount/layer effects both already no-op without a `provider`
559
592
  * (see their guards below), so swapping in `fallback` content here is purely
560
593
  * a render-output change -- it does not touch the mount lifecycle.
594
+ *
595
+ * `mapControls`: rendered as a plain (non-portaled) React overlay laid over the WHOLE map area --
596
+ * see `IListingMapProps.mapControls`'s own doc comment. Deliberately NOT a child of the ref'd
597
+ * container passed to `provider.mount()`: a real map SDK (e.g. Google Maps) takes ownership of
598
+ * that element's contents, so `mapControls` is instead a sibling inside an outer wrapper `<div>`
599
+ * (`wrapperRef`), absolutely positioned over it via CSS -- never competing with the map SDK for
600
+ * that node's children. `null`/`undefined` renders nothing extra (no wrapper divs at all), so
601
+ * this is a fully backward-compatible addition.
602
+ *
603
+ * Because `mapControls` is a SIBLING of the map mount div rather than a descendant, a
604
+ * fullscreen/zoom button rendered through it needs `toggleFullscreen()` to target an element that
605
+ * CONTAINS both of them -- the Fullscreen API only shows the target element and its descendants,
606
+ * so fullscreening the mount div alone would make any such button disappear the instant
607
+ * fullscreen is entered. `wrapperRef` (the outer `<div>` itself) is passed as `fullscreenTarget`
608
+ * in the mount effect above for exactly this reason -- see `MapInitOptions.fullscreenTarget`'s
609
+ * doc comment.
561
610
  */
562
611
  declare function ListingMap(props: IListingMapProps): react.JSX.Element;
563
612
 
@@ -646,6 +695,7 @@ declare function useListingState<TEntity = unknown, TFilters = unknown>(): {
646
695
  readonly north: number;
647
696
  } | null;
648
697
  readonly selection: EntityId | null;
698
+ readonly hovered: EntityId | null;
649
699
  readonly pagination: {
650
700
  readonly mode: PaginationMode;
651
701
  readonly loading: boolean;
@@ -687,7 +737,12 @@ declare function useListingFilters<TFilters = unknown>(): {
687
737
  setField: <K_2 extends keyof TFilters>(key: K_2, value: TFilters[K_2]) => Promise<void>;
688
738
  };
689
739
 
690
- /** Map-facing slice of listing state (bounds, per-dataset points) plus the two engine actions that drive them. */
740
+ /**
741
+ * Map-facing slice of listing state (bounds, per-dataset points, hovered
742
+ * marker id) plus the engine actions that drive them. `hovered` is bound to
743
+ * the primary dataset (`engine.primaryDatasetId`) -- a transient
744
+ * highlight-on-hover affordance, independent of `selectPoint`'s `selection`.
745
+ */
691
746
  declare function useListingMap(): {
692
747
  bounds: {
693
748
  readonly west: number;
@@ -705,8 +760,13 @@ declare function useListingMap(): {
705
760
  readonly entity: unknown;
706
761
  }[];
707
762
  };
763
+ hovered: EntityId | null;
708
764
  loadPoints: (bounds: Bounds) => Promise<void>;
709
- selectPoint: (datasetId: string, id: EntityId) => void;
765
+ selectPoint: (datasetId: string, id: EntityId | null) => void;
766
+ setHovered: (id: EntityId | null) => void;
767
+ zoomIn: () => void | undefined;
768
+ zoomOut: () => void | undefined;
769
+ toggleFullscreen: () => void | undefined;
710
770
  };
711
771
 
712
772
  /**
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
1
  "use client";
2
- import{A as J,B as K,C as N,R as f,a as w,b as F,c as S,d as Q,e as x,f as T,g as L,h as H,i as O,j as k,k as q,l as E,m as C,n as U,o as B,p as I,q as l,r as G,s as n,t as a,u as R,v as $,w as j,x as A,y as z,z as D}from"./chunk-CZCVR4OW.js";var m=(e=>(e.Paged="paged",e.Infinite="infinite",e))(m||{});var g=(s=>(s.FiltersChanged="FiltersChanged",s.ResultsLoaded="ResultsLoaded",s.PointClicked="PointClicked",s.BoundsChanged="BoundsChanged",s.LayerToggled="LayerToggled",s))(g||{});var y=class{query;listeners=new Set;constructor(t={}){this.query={...t}}getQuery(){return{...this.query}}setQuery(t){this.query={...t},this.notify()}subscribe(t){return this.listeners.add(t),()=>{this.listeners.delete(t)}}notify(){for(let t of[...this.listeners])t()}};function P(r,t){let e=new Set([...Object.keys(r),...Object.keys(t)]);for(let i of e)if(r[i]!==t[i])return!1;return!0}var c=class{history;toQueryFn;toFiltersFn;hydrateOnStart;isSyncing=!1;unsubscribeEngine=null;unsubscribeHistory=null;constructor(t){this.history=t.history,this.toQueryFn=t.toQuery,this.toFiltersFn=t.toFilters,this.hydrateOnStart=t.hydrateOnStart??!0}start(t){this.stop(),this.unsubscribeEngine=t.subscribe(()=>{this.isSyncing||this.syncEngineToHistory(t)}),this.unsubscribeHistory=this.history.subscribe(()=>{this.isSyncing||this.withSyncGuard(()=>{this.applyFiltersSafely(t,this.toFiltersFn(this.history.getQuery()))})}),this.hydrateOnStart&&this.withSyncGuard(()=>{this.applyFiltersSafely(t,this.toFiltersFn(this.history.getQuery()))})}stop(){this.unsubscribeEngine?.(),this.unsubscribeEngine=null,this.unsubscribeHistory?.(),this.unsubscribeHistory=null}syncEngineToHistory(t){let e=this.toQueryFn(t.state.filters);P(e,this.history.getQuery())||this.withSyncGuard(()=>this.history.setQuery(e))}applyFiltersSafely(t,e){Promise.resolve(t.applyFilters(e)).catch(()=>{})}withSyncGuard(t){this.isSyncing=!0;try{t()}finally{this.isSyncing=!1}}};var p=class{mode;constructor(t={}){this.mode=t.mode??"replace"}getQuery(){if(typeof window>"u")return{};let t=new URLSearchParams(window.location.search),e={};for(let[i,o]of t)o!==""&&(e[i]=o);return e}setQuery(t){if(typeof window>"u")return;let e=new URLSearchParams;for(let[h,u]of Object.entries(t))u===void 0||u===""||e.set(h,u);let i=e.toString(),o=i?`?${i}`:"";if(o===window.location.search)return;let s=`${window.location.pathname}${o}${window.location.hash}`;this.mode==="push"?window.history.pushState(window.history.state,"",s):window.history.replaceState(window.history.state,"",s)}subscribe(t){return typeof window>"u"?()=>{}:(window.addEventListener("popstate",t),()=>{window.removeEventListener("popstate",t)})}};import{jsx as b}from"react/jsx-runtime";function M({children:r}){let{Toolbar:t}=l();return b(t,{children:r})}import{useCallback as d}from"react";function ot(){let r=n(),t=a(),e=d(o=>r.loadPoints(o),[r]),i=d((o,s)=>r.selectPoint(o,s),[r]);return{bounds:t.bounds,points:t.points,loadPoints:e,selectPoint:i}}import{useCallback as v}from"react";function yt(r){let t=n(),e=a(),i=v(()=>t.toggleLayer(r),[t,r]);return{visible:e.layers[r]??!0,points:e.points[r]??[],toggle:i}}export{p as BrowserHistoryPort,S as DatasetRegistry,F as FilterRegistry,f as ListingApp,I as ListingComponentsProvider,T as ListingConfig,L as ListingEngine,G as ListingEngineContext,g as ListingEventType,$ as ListingFilters,A as ListingList,z as ListingMap,D as ListingPagination,N as ListingProvider,J as ListingResultHeader,w as ListingStore,M as ListingToolbar,y as MemoryHistoryPort,m as PaginationMode,Q as TypedEmitter,c as UrlSyncController,H as composeListingProviders,x as listingDefaultConfig,n as useListing,l as useListingComponents,K as useListingEvent,R as useListingFilters,yt as useListingLayer,ot as useListingMap,j as useListingResults,a as useListingState,O as withConfig,q as withDataset,E as withFilters,U as withInitialFilters,k as withMap,B as withPrimaryDataset,C as withUrlSync};
2
+ import{A as N,B as V,C as W,D as X,S as g,a as S,b as Q,c as x,d as T,e as L,f as H,g as O,h as E,i as k,j as q,k as I,l as C,m as U,n as B,o as z,p as G,q as R,r as p,s as $,t as u,u as y,v as j,w as A,x as D,y as J,z as K}from"./chunk-YGFE5EQQ.js";var P=(r=>(r.Paged="paged",r.Infinite="infinite",r))(P||{});var v=(i=>(i.FiltersChanged="FiltersChanged",i.ResultsLoaded="ResultsLoaded",i.PointClicked="PointClicked",i.BoundsChanged="BoundsChanged",i.LayerToggled="LayerToggled",i))(v||{});var d=class{query;listeners=new Set;constructor(t={}){this.query={...t}}getQuery(){return{...this.query}}setQuery(t){this.query={...t},this.notify()}subscribe(t){return this.listeners.add(t),()=>{this.listeners.delete(t)}}notify(){for(let t of[...this.listeners])t()}};function b(e,t){let r=new Set([...Object.keys(e),...Object.keys(t)]);for(let s of r)if(e[s]!==t[s])return!1;return!0}var h=class{history;toQueryFn;toFiltersFn;hydrateOnStart;isSyncing=!1;unsubscribeEngine=null;unsubscribeHistory=null;constructor(t){this.history=t.history,this.toQueryFn=t.toQuery,this.toFiltersFn=t.toFilters,this.hydrateOnStart=t.hydrateOnStart??!0}start(t){this.stop(),this.unsubscribeEngine=t.subscribe(()=>{this.isSyncing||this.syncEngineToHistory(t)}),this.unsubscribeHistory=this.history.subscribe(()=>{this.isSyncing||this.withSyncGuard(()=>{this.applyFiltersSafely(t,this.toFiltersFn(this.history.getQuery()))})}),this.hydrateOnStart&&this.withSyncGuard(()=>{this.applyFiltersSafely(t,this.toFiltersFn(this.history.getQuery()))})}stop(){this.unsubscribeEngine?.(),this.unsubscribeEngine=null,this.unsubscribeHistory?.(),this.unsubscribeHistory=null}syncEngineToHistory(t){let r=this.toQueryFn(t.state.filters);b(r,this.history.getQuery())||this.withSyncGuard(()=>this.history.setQuery(r))}applyFiltersSafely(t,r){Promise.resolve(t.applyFilters(r)).catch(()=>{})}withSyncGuard(t){this.isSyncing=!0;try{t()}finally{this.isSyncing=!1}}};var m=class{mode;constructor(t={}){this.mode=t.mode??"replace"}getQuery(){if(typeof window>"u")return{};let t=new URLSearchParams(window.location.search),r={};for(let[s,o]of t)o!==""&&(r[s]=o);return r}setQuery(t){if(typeof window>"u")return;let r=new URLSearchParams;for(let[c,a]of Object.entries(t))a===void 0||a===""||r.set(c,a);let s=r.toString(),o=s?`?${s}`:"";if(o===window.location.search)return;let i=`${window.location.pathname}${o}${window.location.hash}`;this.mode==="push"?window.history.pushState(window.history.state,"",i):window.history.replaceState(window.history.state,"",i)}subscribe(t){return typeof window>"u"?()=>{}:(window.addEventListener("popstate",t),()=>{window.removeEventListener("popstate",t)})}};import{jsx as F}from"react/jsx-runtime";function rt({children:e}){let{Toolbar:t}=p();return F(t,{children:e})}import{useCallback as n}from"react";function lt(){let e=u(),t=y(),r=n(l=>e.loadPoints(l),[e]),s=n((l,f)=>e.selectPoint(l,f),[e]),o=n(l=>e.setHovered(e.primaryDatasetId,l),[e]),i=n(()=>e.map?.zoomIn(),[e]),c=n(()=>e.map?.zoomOut(),[e]),a=n(()=>e.map?.toggleFullscreen(),[e]);return{bounds:t.bounds,points:t.points,hovered:t.hovered,loadPoints:r,selectPoint:s,setHovered:o,zoomIn:i,zoomOut:c,toggleFullscreen:a}}import{useCallback as w}from"react";function dt(e){let t=u(),r=y(),s=w(()=>t.toggleLayer(e),[t,e]);return{visible:r.layers[e]??!0,points:r.points[e]??[],toggle:s}}export{m as BrowserHistoryPort,x as DatasetRegistry,G as FallbackPopup,Q as FilterRegistry,g as ListingApp,R as ListingComponentsProvider,H as ListingConfig,O as ListingEngine,$ as ListingEngineContext,v as ListingEventType,A as ListingFilters,J as ListingList,K as ListingMap,N as ListingPagination,X as ListingProvider,V as ListingResultHeader,S as ListingStore,rt as ListingToolbar,d as MemoryHistoryPort,P as PaginationMode,T as TypedEmitter,h as UrlSyncController,E as composeListingProviders,L as listingDefaultConfig,u as useListing,p as useListingComponents,W as useListingEvent,j as useListingFilters,dt as useListingLayer,lt as useListingMap,D as useListingResults,y as useListingState,k as withConfig,I as withDataset,C as withFilters,B as withInitialFilters,q as withMap,z as withPrimaryDataset,U as withUrlSync};