react-listing-engine 0.6.4 → 0.6.6

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.
Files changed (48) hide show
  1. package/README.md +54 -65
  2. package/dist/chunk-OXSYNZAJ.js +2 -0
  3. package/dist/chunk-PE27NATS.cjs +2 -0
  4. package/dist/index.cjs +2 -2
  5. package/dist/index.d.cts +95 -16
  6. package/dist/index.d.ts +95 -16
  7. package/dist/index.js +1 -1
  8. package/dist/{listing-app-wmMuDlVU.d.ts → listing-app-4Vs_SMNl.d.cts} +146 -26
  9. package/dist/{listing-app-DJbvx3oe.d.cts → listing-app-CkEGdUV9.d.ts} +146 -26
  10. package/dist/map-provider.interface-DT-v1plm.d.cts +67 -0
  11. package/dist/map-provider.interface-DT-v1plm.d.ts +67 -0
  12. package/dist/maps/google/index.d.cts +1 -2
  13. package/dist/maps/google/index.d.ts +1 -2
  14. package/dist/styled/index.cjs +1 -1
  15. package/dist/styled/index.d.cts +7 -10
  16. package/dist/styled/index.d.ts +7 -10
  17. package/dist/styled/index.js +1 -1
  18. package/dist/testing/index.d.cts +1 -2
  19. package/dist/testing/index.d.ts +1 -2
  20. package/package.json +3 -14
  21. package/dist/chunk-2VUHLHHX.cjs +0 -2
  22. package/dist/chunk-35KYEBAC.js +0 -2
  23. package/dist/chunk-5FBI2WIM.js +0 -2
  24. package/dist/chunk-6PZHSHU3.js +0 -2
  25. package/dist/chunk-CGT3RHJ7.js +0 -2
  26. package/dist/chunk-CHNUE46K.cjs +0 -2
  27. package/dist/chunk-EYXV5OMY.cjs +0 -2
  28. package/dist/chunk-LCQZIWBO.cjs +0 -2
  29. package/dist/chunk-R3FX2V3N.js +0 -2
  30. package/dist/chunk-RXHR66FS.cjs +0 -2
  31. package/dist/components-provider-CF0Mo0B8.d.cts +0 -120
  32. package/dist/components-provider-CjMxkxrP.d.ts +0 -120
  33. package/dist/entity-adapter.interface-BDgbSxhq.d.cts +0 -33
  34. package/dist/entity-adapter.interface-BDgbSxhq.d.ts +0 -33
  35. package/dist/listing-config-options.interface-ZJYY_ZvR.d.cts +0 -12
  36. package/dist/listing-config-options.interface-ZJYY_ZvR.d.ts +0 -12
  37. package/dist/map-provider.interface-BMnwW3ob.d.cts +0 -37
  38. package/dist/map-provider.interface-BxexMT3X.d.ts +0 -37
  39. package/dist/presets/rental/index.cjs +0 -2
  40. package/dist/presets/rental/index.d.cts +0 -266
  41. package/dist/presets/rental/index.d.ts +0 -266
  42. package/dist/presets/rental/index.js +0 -2
  43. package/dist/shadcn/index.cjs +0 -2
  44. package/dist/shadcn/index.d.cts +0 -261
  45. package/dist/shadcn/index.d.ts +0 -261
  46. package/dist/shadcn/index.js +0 -2
  47. package/dist/url-sync.controller-CsU_QxoS.d.cts +0 -89
  48. package/dist/url-sync.controller-DX67JivW.d.ts +0 -89
package/dist/index.d.ts CHANGED
@@ -1,15 +1,9 @@
1
- import { P as Page, B as Bounds, E as EntityId, M as MapPoint, Q as QueryParams, L as LatLng } from './entity-adapter.interface-BDgbSxhq.js';
2
- export { a as EntityAdapter, b as PageRequest } from './entity-adapter.interface-BDgbSxhq.js';
3
- import { U as Unsubscribe, M as MapProvider } from './map-provider.interface-BxexMT3X.js';
4
- export { a as MapHandle, b as MapInitOptions, R as RenderedLayer } from './map-provider.interface-BxexMT3X.js';
5
- import { D as DatasetDefinition, F as FilterRegistry, I as IListingToolbarProps } from './components-provider-CjMxkxrP.js';
6
- export { C as ClusterOptions, a as FilterControlProps, b as FilterDefinition, c as IListingCardProps, d as IListingComponents, e as IListingEmptyProps, f as IListingFilterPanelProps, g as IListingLoadingProps, h as IListingMarkerProps, i as IListingPopupProps, j as IListingResultHeaderProps, k as IListingSearchProps, l as IListingSidebarProps, L as ListingComponentsProvider, M as MarkerRenderer, u as useListingComponents } from './components-provider-CjMxkxrP.js';
7
- import { P as PaginationMode, I as IListingConfigOptions } from './listing-config-options.interface-ZJYY_ZvR.js';
8
- import { H as HistoryPort, U as UrlSyncController } from './url-sync.controller-DX67JivW.js';
9
- export { a as UrlSyncEngine, b as UrlSyncOptions } from './url-sync.controller-DX67JivW.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-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-CkEGdUV9.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-CkEGdUV9.js';
10
5
  import * as react from 'react';
11
6
  import { ReactNode } from 'react';
12
- export { L as ListingApp, a as ListingAppProps } from './listing-app-wmMuDlVU.js';
13
7
 
14
8
  declare enum ListingEventType {
15
9
  FiltersChanged = "FiltersChanged",
@@ -216,6 +210,18 @@ declare class ListingEngine<TEntity, TFilters> {
216
210
  private clearDebounce;
217
211
  }
218
212
 
213
+ /**
214
+ * DOM-agnostic abstraction over "the URL's query string" — or, in tests/SSR,
215
+ * an in-memory stand-in (`MemoryHistoryPort`). `UrlSyncController` talks to
216
+ * this interface only, never to `window.location`/`history` directly, so it
217
+ * stays framework- and environment-free like the rest of `src/core`.
218
+ */
219
+ interface HistoryPort {
220
+ getQuery(): QueryParams;
221
+ setQuery(params: QueryParams): void;
222
+ subscribe(cb: () => void): () => void;
223
+ }
224
+
219
225
  /**
220
226
  * In-memory `HistoryPort` — holds `QueryParams` in a plain field instead of
221
227
  * the browser URL. Used by tests (fast, no DOM/jsdom `history` needed) and by
@@ -231,6 +237,79 @@ declare class MemoryHistoryPort implements HistoryPort {
231
237
  private notify;
232
238
  }
233
239
 
240
+ interface UrlSyncEngine<TFilters> {
241
+ subscribe(cb: () => void): () => void;
242
+ readonly state: {
243
+ readonly filters: TFilters;
244
+ };
245
+ applyFilters(patch: Partial<TFilters>): Promise<void> | void;
246
+ }
247
+ interface UrlSyncOptions<TFilters> {
248
+ history: HistoryPort;
249
+ toQuery(filters: TFilters): QueryParams;
250
+ toFilters(query: QueryParams): Partial<TFilters>;
251
+ hydrateOnStart?: boolean;
252
+ }
253
+ /**
254
+ * Bidirectional, DOM-agnostic sync between an engine's `filters` and a
255
+ * `HistoryPort`'s query params. Framework-free: talks to `UrlSyncEngine`
256
+ * (a structural subset `ListingEngine` satisfies) and `HistoryPort`, nothing
257
+ * else — no `window`, no React.
258
+ *
259
+ * OPTIONAL, not the primary path: `styled/listing-app.tsx`'s turnkey
260
+ * `ListingApp` (the package's main-entry default) does NOT wire this up —
261
+ * it uses an event-based URL API instead (`initialFilters` in,
262
+ * `onFiltersChange` out; see that file's doc comment), so the library never
263
+ * touches `window.history` by default. This class remains exported for
264
+ * consumers who explicitly want the library to own history writes/reads
265
+ * itself, by wiring it directly against a hand-built engine.
266
+ *
267
+ * Echo-loop guard: both subscriptions below are driven by the SAME
268
+ * `isSyncing` flag. `ListingEngine.applyFilters()` and `MemoryHistoryPort`
269
+ * (and any real browser HistoryPort) both notify their subscribers
270
+ * SYNCHRONOUSLY as part of the write (`store.setFilters()` -> `notify()`
271
+ * happens before any debounce timer, and `MemoryHistoryPort.setQuery()`
272
+ * notifies before returning) — so when this controller initiates a write on
273
+ * one side, the reciprocal subscription on the other side fires within the
274
+ * very same call stack, before `isSyncing` is reset. Wrapping each
275
+ * controller-initiated write in `isSyncing = true; ...; isSyncing = false`
276
+ * (via try/finally, so a throwing `toQuery`/`toFilters`/notify can't leave it
277
+ * stuck) means that reciprocal callback observes `isSyncing === true` and
278
+ * short-circuits instead of writing back — one hop each direction, never a
279
+ * cascade. `hydrateOnStart`'s initial engine write is wrapped the same way,
280
+ * since it must not immediately echo the just-hydrated filters back out to
281
+ * history as a redundant `setQuery`.
282
+ *
283
+ * `isSyncing` only covers that SYNCHRONOUS window, though — the real
284
+ * `ListingEngine.applyFilters()` notifies AGAIN, asynchronously: after
285
+ * `await adapter.list(...)` resolves, `store.setResults()` and
286
+ * `store.setLoading(false)` each call `notify()`, well after `isSyncing` has
287
+ * already been reset to `false` by the `withSyncGuard` that kicked the query
288
+ * off. Left unguarded, that async tail would fire the engine subscription
289
+ * below and echo an identical (but spurious) `history.setQuery(...)` on
290
+ * every completed query. Rather than widening `isSyncing` to cover the whole
291
+ * async query (which would also swallow legitimate concurrent history
292
+ * changes that land mid-query), `syncEngineToHistory` is idempotent BY
293
+ * VALUE instead: it computes the target query and skips the write entirely
294
+ * when it already matches `history.getQuery()` — timing-independent, so it
295
+ * suppresses the async-tail echo without touching `isSyncing` at all.
296
+ */
297
+ declare class UrlSyncController<TFilters> {
298
+ private readonly history;
299
+ private readonly toQueryFn;
300
+ private readonly toFiltersFn;
301
+ private readonly hydrateOnStart;
302
+ private isSyncing;
303
+ private unsubscribeEngine;
304
+ private unsubscribeHistory;
305
+ constructor(opts: UrlSyncOptions<TFilters>);
306
+ start(engine: UrlSyncEngine<TFilters>): void;
307
+ stop(): void;
308
+ private syncEngineToHistory;
309
+ private applyFiltersSafely;
310
+ private withSyncGuard;
311
+ }
312
+
234
313
  /**
235
314
  * Aggregated provider props — the composition entry point of
236
315
  * react-listing-engine, mirroring `react-wizard-engine`'s
@@ -299,8 +378,8 @@ interface IListingFiltersProps {
299
378
  * styling hook -- this component stays structure-only, so it never bakes
300
379
  * in its own layout beyond the `space-y-5` fallback below. Pass a
301
380
  * horizontal row (e.g. `"flex flex-wrap items-end gap-3"`) to flow filter
302
- * groups inline instead of stacking them, as `/shadcn`'s `ListingLayout`
303
- * does for its top filter bar.
381
+ * groups inline instead of stacking them, as the `/styled` adapter's
382
+ * `StyledListingLayout` does for its top filter bar.
304
383
  */
305
384
  className?: string;
306
385
  /** ClassName applied to each individual filter group's wrapper `<div>` (including the string-placeholder case). */
@@ -325,7 +404,7 @@ interface IListingFiltersProps {
325
404
  * `"text"`/`"range"`/`"toggle"`): there is no shared named-control registry
326
405
  * yet, so this renders an inert `<div data-filter={def.key} />` placeholder.
327
406
  * Wiring a real named-control registry (so `"range"` etc. resolve to an
328
- * actual control, likely in the `/shadcn` adapter) is a documented future
407
+ * actual control) is a documented future
329
408
  * enhancement, not attempted in this task.
330
409
  *
331
410
  * Each filter group is wrapped in its own `<div>`: when `def.label` is set,
@@ -491,8 +570,8 @@ declare function ListingMap(props: IListingMapProps): react.JSX.Element;
491
570
  *
492
571
  * Renders a plain `<button>` rather than an injected component: `useListingComponents()`
493
572
  * (`IListingComponents`) has no `Button` slot yet, so there is nothing to
494
- * delegate to here. Wiring this up to a real Button slot (and to the shadcn
495
- * adapter's styled Button) is a documented future enhancement once that slot
573
+ * delegate to here. Wiring this up to a real Button slot (and a styled Button
574
+ * in the `/styled` adapter) is a documented future enhancement once that slot
496
575
  * exists.
497
576
  */
498
577
  declare function ListingPagination(): react.JSX.Element | null;
@@ -679,4 +758,4 @@ interface IListingProviderComponentProps<TFilters> extends IListingProviderProps
679
758
  */
680
759
  declare function ListingProvider<TEntity, TFilters>(props: IListingProviderComponentProps<TFilters>): react.JSX.Element | null;
681
760
 
682
- export { Bounds, BrowserHistoryPort, type BrowserHistoryPortOptions, DatasetDefinition, DatasetRegistry, EntityId, FilterRegistry, HistoryPort, IListingConfigOptions, type IListingFiltersProps, type IListingMapProps, type IListingProviderProps, IListingToolbarProps, LatLng, ListingConfig, ListingEngine, ListingEngineContext, type ListingEngineOptions, type ListingEvent, ListingEventType, ListingFilters, ListingList, ListingMap, ListingPagination, ListingProvider, type ListingProviderMod, ListingResultHeader, type ListingState, ListingStore, type ListingStoreInit, ListingToolbar, MapPoint, MapProvider, MemoryHistoryPort, Page, PaginationMode, QueryParams, TypedEmitter, Unsubscribe, UrlSyncController, composeListingProviders, listingDefaultConfig, useListing, useListingEvent, useListingFilters, useListingLayer, useListingMap, useListingResults, useListingState, withConfig, withDataset, withFilters, withInitialFilters, withMap, withPrimaryDataset, withUrlSync };
761
+ export { Bounds, BrowserHistoryPort, type BrowserHistoryPortOptions, DatasetDefinition, DatasetRegistry, EntityId, FilterRegistry, type HistoryPort, IListingConfigOptions, type IListingFiltersProps, type IListingMapProps, type IListingProviderProps, IListingToolbarProps, LatLng, ListingConfig, ListingEngine, ListingEngineContext, type ListingEngineOptions, type ListingEvent, ListingEventType, ListingFilters, ListingList, ListingMap, ListingPagination, ListingProvider, type ListingProviderMod, ListingResultHeader, type ListingState, ListingStore, type ListingStoreInit, ListingToolbar, MapPoint, MapProvider, MemoryHistoryPort, Page, PaginationMode, QueryParams, TypedEmitter, Unsubscribe, UrlSyncController, type UrlSyncEngine, type UrlSyncOptions, composeListingProviders, listingDefaultConfig, useListing, useListingEvent, useListingFilters, useListingLayer, useListingMap, useListingResults, useListingState, withConfig, withDataset, withFilters, withInitialFilters, withMap, withPrimaryDataset, withUrlSync };
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
1
  "use client";
2
- import{a as O,p as m}from"./chunk-CGT3RHJ7.js";import{A as N,B as U,a as y,b as P,c as L,d as h,e as b,f as x,g as C,h as I,i as k,j as q,k as v,l as B,m as S,n as A,o as F,p as T,q as p,r as w,s,t as i,u as H,v as z,w as D,x as G,y as J,z as K}from"./chunk-R3FX2V3N.js";import{a as R}from"./chunk-5FBI2WIM.js";import{a as Q}from"./chunk-35KYEBAC.js";var d=(o=>(o.Paged="paged",o.Infinite="infinite",o))(d||{});var f=(r=>(r.FiltersChanged="FiltersChanged",r.ResultsLoaded="ResultsLoaded",r.PointClicked="PointClicked",r.BoundsChanged="BoundsChanged",r.LayerToggled="LayerToggled",r))(f||{});var u=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()}};import{jsx as c}from"react/jsx-runtime";function Z({children:e}){let{Toolbar:t}=p();return c(t,{children:e})}import{useCallback as l}from"react";function tt(){let e=s(),t=i(),o=l(a=>e.loadPoints(a),[e]),n=l((a,r)=>e.selectPoint(a,r),[e]);return{bounds:t.bounds,points:t.points,loadPoints:o,selectPoint:n}}import{useCallback as g}from"react";function it(e){let t=s(),o=i(),n=g(()=>t.toggleLayer(e),[t,e]);return{visible:o.layers[e]??!0,points:o.points[e]??[],toggle:n}}export{R as BrowserHistoryPort,L as DatasetRegistry,P as FilterRegistry,m as ListingApp,T as ListingComponentsProvider,x as ListingConfig,C as ListingEngine,w as ListingEngineContext,f as ListingEventType,z as ListingFilters,G as ListingList,J as ListingMap,K as ListingPagination,U as ListingProvider,N as ListingResultHeader,y as ListingStore,Z as ListingToolbar,u as MemoryHistoryPort,d as PaginationMode,h as TypedEmitter,Q as UrlSyncController,I as composeListingProviders,b as listingDefaultConfig,s as useListing,p as useListingComponents,O as useListingEvent,H as useListingFilters,it as useListingLayer,tt as useListingMap,D as useListingResults,i as useListingState,k as withConfig,v as withDataset,B as withFilters,A as withInitialFilters,q as withMap,F as withPrimaryDataset,S as withUrlSync};
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-OXSYNZAJ.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};
@@ -1,9 +1,132 @@
1
1
  import * as react from 'react';
2
- import { ReactNode } from 'react';
3
- import { L as LatLng } from './entity-adapter.interface-BDgbSxhq.js';
4
- import { M as MapProvider } from './map-provider.interface-BxexMT3X.js';
5
- import { D as DatasetDefinition, F as FilterRegistry, d as IListingComponents } from './components-provider-CjMxkxrP.js';
6
- import { I as IListingConfigOptions } from './listing-config-options.interface-ZJYY_ZvR.js';
2
+ import { ComponentType, ReactNode } from 'react';
3
+ import { b as EntityAdapter, M as MapPoint, L as LatLng, a as MapProvider } from './map-provider.interface-DT-v1plm.cjs';
4
+
5
+ interface FilterControlProps<TValue> {
6
+ value: TValue;
7
+ onChange(next: TValue): void;
8
+ }
9
+ interface FilterDefinition<TFilters, TValue = unknown> {
10
+ key: string;
11
+ order: number;
12
+ render: string | ComponentType<FilterControlProps<TValue>>;
13
+ toParams(value: TValue): Partial<TFilters>;
14
+ fromParams(filters: TFilters): TValue;
15
+ isActive?(filters: TFilters): boolean;
16
+ /** Optional human-readable label rendered above the control by `ListingFilters`. Omit for an unlabeled filter (backward compatible). */
17
+ label?: string;
18
+ }
19
+
20
+ interface ClusterOptions {
21
+ maxZoom?: number;
22
+ radius?: number;
23
+ }
24
+ interface MarkerRenderer<TEntity> {
25
+ iconUrl?(entity: TEntity): string;
26
+ element?(entity: TEntity): HTMLElement;
27
+ onClick?(entity: TEntity): void;
28
+ }
29
+ interface DatasetDefinition<TEntity, TFilters> {
30
+ id: string;
31
+ adapter: EntityAdapter<TEntity, TFilters>;
32
+ marker: MarkerRenderer<TEntity>;
33
+ clustering?: ClusterOptions | false;
34
+ visible?: () => boolean;
35
+ }
36
+
37
+ declare enum PaginationMode {
38
+ Paged = "paged",
39
+ Infinite = "infinite"
40
+ }
41
+
42
+ interface IListingConfigOptions {
43
+ pagination: PaginationMode;
44
+ pageSize: number;
45
+ debounceMs: number;
46
+ }
47
+
48
+ /**
49
+ * Framework-free registry for `FilterDefinition`s: programmatic add / remove /
50
+ * reorder / replace, plus folding raw control values into `TFilters`
51
+ * (`toFilters`) and reporting which registered filters currently affect an
52
+ * applied `TFilters` (`activeKeys`).
53
+ *
54
+ * Defs are stored by VALUE (shallow-cloned on `add`/`replace`), never by the
55
+ * caller's original reference — `reorder()` rewrites `order` in place on the
56
+ * registry's own copy. This is deliberate: the same `FilterDefinition` object
57
+ * can legitimately be registered in more than one `FilterRegistry` instance
58
+ * (e.g. two listing pages sharing a base filter set), and without cloning,
59
+ * one registry's `reorder()` would silently mutate `.order` on the shared
60
+ * object and bleed into every other registry (and the caller) holding it.
61
+ */
62
+ declare class FilterRegistry<TFilters> {
63
+ private readonly defs;
64
+ add<TValue = unknown>(def: FilterDefinition<TFilters, TValue>): this;
65
+ remove(key: string): this;
66
+ replace<TValue = unknown>(key: string, def: FilterDefinition<TFilters, TValue>): this;
67
+ reorder(keys: string[]): this;
68
+ list(): FilterDefinition<TFilters>[];
69
+ has(key: string): boolean;
70
+ toFilters(values: Record<string, unknown>): TFilters;
71
+ activeKeys(filters: TFilters): string[];
72
+ }
73
+
74
+ interface IListingCardProps {
75
+ item: unknown;
76
+ selected?: boolean;
77
+ onSelect?: () => void;
78
+ }
79
+ interface IListingMarkerProps {
80
+ point: MapPoint<unknown>;
81
+ }
82
+ interface IListingPopupProps {
83
+ entity: unknown;
84
+ onClose?: () => void;
85
+ }
86
+ interface IListingSidebarProps {
87
+ children?: ReactNode;
88
+ }
89
+ interface IListingFilterPanelProps {
90
+ children?: ReactNode;
91
+ }
92
+ interface IListingSearchProps {
93
+ value: string;
94
+ onChange(value: string): void;
95
+ placeholder?: string;
96
+ }
97
+ interface IListingEmptyProps {
98
+ }
99
+ interface IListingLoadingProps {
100
+ }
101
+ interface IListingResultHeaderProps {
102
+ count: number;
103
+ total?: number;
104
+ }
105
+ interface IListingToolbarProps {
106
+ children?: ReactNode;
107
+ }
108
+ interface IListingComponents {
109
+ Card: ComponentType<IListingCardProps>;
110
+ Marker: ComponentType<IListingMarkerProps>;
111
+ Popup: ComponentType<IListingPopupProps>;
112
+ Sidebar: ComponentType<IListingSidebarProps>;
113
+ FilterPanel: ComponentType<IListingFilterPanelProps>;
114
+ Search: ComponentType<IListingSearchProps>;
115
+ Empty: ComponentType<IListingEmptyProps>;
116
+ Loading: ComponentType<IListingLoadingProps>;
117
+ ResultHeader: ComponentType<IListingResultHeaderProps>;
118
+ Toolbar: ComponentType<IListingToolbarProps>;
119
+ }
120
+ /**
121
+ * Injection point for custom-component overrides. Every slot is optional —
122
+ * anything not provided falls back to the (unstyled) default. Mirrors
123
+ * `react-wizard-engine`'s `WizardComponentsProvider`: explicit per-slot
124
+ * `provided ?? defaults.X` merge, not a generic/reflective loop.
125
+ */
126
+ declare function ListingComponentsProvider(props: Partial<IListingComponents> & {
127
+ children: ReactNode;
128
+ }): react.JSX.Element;
129
+ declare function useListingComponents(): IListingComponents;
7
130
 
8
131
  type BottomNavView = 'list' | 'map';
9
132
  interface IBottomNavAction {
@@ -29,8 +152,8 @@ declare function BottomNav({ view, onViewChange }: IBottomNavProps): react.JSX.E
29
152
 
30
153
  interface IStyledListingLayoutProps {
31
154
  /**
32
- * Optional header search box, LIBRARY-wired (unlike `/shadcn`'s
33
- * consumer-managed `search`): name the `TFilters` field it drives via
155
+ * Optional header search box, LIBRARY-wired: name the `TFilters` field it
156
+ * drives via
34
157
  * `filterKey`, and the layout reads the current value from the engine's
35
158
  * filters and writes edits back with `applyFilters({ [filterKey]: value ||
36
159
  * undefined })`. Rendered in BOTH the desktop filter bar and the mobile
@@ -61,12 +184,11 @@ interface IStyledListingLayoutProps {
61
184
  className?: string;
62
185
  }
63
186
  /**
64
- * Full, responsive, Tailwind-free listing experience -- the `/styled`
65
- * counterpart to `/shadcn`'s `ListingLayout`, built from the same
187
+ * Full, responsive, Tailwind-free listing experience -- built from the
66
188
  * structure-only compound components (`~/react`) plus the injected
67
- * `Styled*` slot components, but with a richer mobile experience: a bottom
68
- * nav (`BottomNav`) and a bottom sheet (`BottomSheet`) for filters, instead
69
- * of `/shadcn`'s inline mobile toggle bar. Every class used here is one of
189
+ * `Styled*` slot components, with a rich mobile experience: a bottom
190
+ * nav (`BottomNav`) and a bottom sheet (`BottomSheet`) for filters. Every
191
+ * class used here is one of
70
192
  * the `.rle-*` layout classes added to `styles.css` alongside this file --
71
193
  * no Tailwind, no inline styles, no other stylesheet required.
72
194
  *
@@ -98,18 +220,17 @@ interface IStyledListingLayoutProps {
98
220
  * control already applies live via its own `onChange`, so there is nothing
99
221
  * left to commit).
100
222
  * - Fetches the first page itself on mount (`engine.applyFilters({})`) by
101
- * default, exactly like `/shadcn`'s `ListingLayout` -- pass `autoFetch={false}`
223
+ * default -- pass `autoFetch={false}`
102
224
  * to opt out and drive the first fetch yourself.
103
225
  */
104
226
  declare function StyledListingLayout({ search, toolbarEnd, mobileAction, autoFetch, hasMap, mapCenter, mapZoom, className, }: IStyledListingLayoutProps): react.JSX.Element;
105
227
 
106
228
  /**
107
- * Same two-shape `map` prop as `/shadcn`'s `ListingApp` (see that file's
108
- * `useResolvedMap` doc comment for why the `{ apiKey }` shorthand is resolved
109
- * via a dynamic `import()` rather than a static one -- the reasoning is
110
- * identical here). Re-declared rather than imported from `~/shadcn`: the two
111
- * styled adapters are SIBLINGS, not a hierarchy -- `/styled` never depends on
112
- * `/shadcn` (or vice versa), each is self-contained against `~/core`/`~/react`.
229
+ * Two-shape `map` prop: pass a ready `MapProvider`, or the `{ apiKey, mapId? }`
230
+ * shorthand. The shorthand is resolved via a DYNAMIC `import()` of
231
+ * `~/maps/google` (see `useResolvedMap` below) rather than a static one, so an
232
+ * app that never sets `map` doesn't pull `@googlemaps/js-api-loader` into its
233
+ * bundle.
113
234
  */
114
235
  type ListingAppMapProp = {
115
236
  provider: MapProvider;
@@ -133,7 +254,7 @@ interface ListingAppProps<TFilters> {
133
254
  * `withDataset` doc comment.
134
255
  */
135
256
  datasets: DatasetDefinition<any, TFilters>[];
136
- /** e.g. `withRentalFilters()`, or any `(reg) => { reg.add(...); }` callback -- forwarded verbatim to `withFilters`. */
257
+ /** A `(reg) => { reg.add(...); }` callback that registers your filters -- forwarded verbatim to `withFilters`. */
137
258
  filters?: (reg: FilterRegistry<TFilters>) => void;
138
259
  /** A ready `MapProvider`, or `{ apiKey, mapId? }` to build a `googleProvider` internally. Omit for no map (the styled layout shows a "Map unavailable" fallback). */
139
260
  map?: ListingAppMapProp;
@@ -177,9 +298,8 @@ interface ListingAppProps<TFilters> {
177
298
  className?: string;
178
299
  }
179
300
  /**
180
- * Turnkey, batteries-included, Tailwind-free entry point -- the `/styled`
181
- * counterpart to `/shadcn`'s `ListingApp`, and (per `src/index.ts`) the
182
- * package's MAIN-ENTRY default: `import { ListingApp } from
301
+ * Turnkey, batteries-included, Tailwind-free entry point -- and (per
302
+ * `src/index.ts`) the package's MAIN-ENTRY default: `import { ListingApp } from
183
303
  * 'react-listing-engine'` gives you this component. Pass datasets + filters +
184
304
  * a map + component overrides, and `ListingApp` composes
185
305
  * `composeListingProviders(...)`, `<ListingProvider>`, the `/styled` defaults,
@@ -200,8 +320,8 @@ interface ListingAppProps<TFilters> {
200
320
  * nesting would silently discard every un-overridden `/styled` default
201
321
  * instead of keeping it.
202
322
  *
203
- * URL SYNC IS EVENT-BASED, NOT INTERNAL: unlike `/shadcn`'s `ListingApp`,
204
- * this component takes no `urlSync` prop and never constructs/starts a
323
+ * URL SYNC IS EVENT-BASED, NOT INTERNAL: this component takes no `urlSync`
324
+ * prop and never constructs/starts a
205
325
  * `UrlSyncController` -- it never touches `window.history`. Instead it
206
326
  * accepts `initialFilters` (hydrate FROM the consumer's URL) and emits
207
327
  * `onFiltersChange` (write TO the consumer's URL/router) -- see both props'
@@ -212,4 +332,4 @@ interface ListingAppProps<TFilters> {
212
332
  */
213
333
  declare function ListingApp<TEntity, TFilters>(props: ListingAppProps<TFilters>): react.JSX.Element | null;
214
334
 
215
- export { BottomNav as B, type IBottomNavAction as I, ListingApp as L, StyledListingLayout as S, type ListingAppProps as a, type BottomNavView as b, type IBottomNavProps as c, type IStyledListingLayoutProps as d, type ListingAppMapProp as e };
335
+ export { BottomNav as B, type ClusterOptions as C, type DatasetDefinition as D, FilterRegistry as F, type IListingConfigOptions as I, ListingApp as L, type MarkerRenderer as M, PaginationMode as P, StyledListingLayout as S, type IListingToolbarProps as a, type FilterControlProps as b, type FilterDefinition as c, type IListingCardProps as d, type IListingComponents as e, type IListingEmptyProps as f, type IListingFilterPanelProps as g, type IListingLoadingProps as h, type IListingMarkerProps as i, type IListingPopupProps as j, type IListingResultHeaderProps as k, type IListingSearchProps as l, type IListingSidebarProps as m, type ListingAppProps as n, ListingComponentsProvider as o, type BottomNavView as p, type IBottomNavAction as q, type IBottomNavProps as r, type IStyledListingLayoutProps as s, type ListingAppMapProp as t, useListingComponents as u };
@@ -1,9 +1,132 @@
1
1
  import * as react from 'react';
2
- import { ReactNode } from 'react';
3
- import { L as LatLng } from './entity-adapter.interface-BDgbSxhq.cjs';
4
- import { M as MapProvider } from './map-provider.interface-BMnwW3ob.cjs';
5
- import { D as DatasetDefinition, F as FilterRegistry, d as IListingComponents } from './components-provider-CF0Mo0B8.cjs';
6
- import { I as IListingConfigOptions } from './listing-config-options.interface-ZJYY_ZvR.cjs';
2
+ import { ComponentType, ReactNode } from 'react';
3
+ import { b as EntityAdapter, M as MapPoint, L as LatLng, a as MapProvider } from './map-provider.interface-DT-v1plm.js';
4
+
5
+ interface FilterControlProps<TValue> {
6
+ value: TValue;
7
+ onChange(next: TValue): void;
8
+ }
9
+ interface FilterDefinition<TFilters, TValue = unknown> {
10
+ key: string;
11
+ order: number;
12
+ render: string | ComponentType<FilterControlProps<TValue>>;
13
+ toParams(value: TValue): Partial<TFilters>;
14
+ fromParams(filters: TFilters): TValue;
15
+ isActive?(filters: TFilters): boolean;
16
+ /** Optional human-readable label rendered above the control by `ListingFilters`. Omit for an unlabeled filter (backward compatible). */
17
+ label?: string;
18
+ }
19
+
20
+ interface ClusterOptions {
21
+ maxZoom?: number;
22
+ radius?: number;
23
+ }
24
+ interface MarkerRenderer<TEntity> {
25
+ iconUrl?(entity: TEntity): string;
26
+ element?(entity: TEntity): HTMLElement;
27
+ onClick?(entity: TEntity): void;
28
+ }
29
+ interface DatasetDefinition<TEntity, TFilters> {
30
+ id: string;
31
+ adapter: EntityAdapter<TEntity, TFilters>;
32
+ marker: MarkerRenderer<TEntity>;
33
+ clustering?: ClusterOptions | false;
34
+ visible?: () => boolean;
35
+ }
36
+
37
+ declare enum PaginationMode {
38
+ Paged = "paged",
39
+ Infinite = "infinite"
40
+ }
41
+
42
+ interface IListingConfigOptions {
43
+ pagination: PaginationMode;
44
+ pageSize: number;
45
+ debounceMs: number;
46
+ }
47
+
48
+ /**
49
+ * Framework-free registry for `FilterDefinition`s: programmatic add / remove /
50
+ * reorder / replace, plus folding raw control values into `TFilters`
51
+ * (`toFilters`) and reporting which registered filters currently affect an
52
+ * applied `TFilters` (`activeKeys`).
53
+ *
54
+ * Defs are stored by VALUE (shallow-cloned on `add`/`replace`), never by the
55
+ * caller's original reference — `reorder()` rewrites `order` in place on the
56
+ * registry's own copy. This is deliberate: the same `FilterDefinition` object
57
+ * can legitimately be registered in more than one `FilterRegistry` instance
58
+ * (e.g. two listing pages sharing a base filter set), and without cloning,
59
+ * one registry's `reorder()` would silently mutate `.order` on the shared
60
+ * object and bleed into every other registry (and the caller) holding it.
61
+ */
62
+ declare class FilterRegistry<TFilters> {
63
+ private readonly defs;
64
+ add<TValue = unknown>(def: FilterDefinition<TFilters, TValue>): this;
65
+ remove(key: string): this;
66
+ replace<TValue = unknown>(key: string, def: FilterDefinition<TFilters, TValue>): this;
67
+ reorder(keys: string[]): this;
68
+ list(): FilterDefinition<TFilters>[];
69
+ has(key: string): boolean;
70
+ toFilters(values: Record<string, unknown>): TFilters;
71
+ activeKeys(filters: TFilters): string[];
72
+ }
73
+
74
+ interface IListingCardProps {
75
+ item: unknown;
76
+ selected?: boolean;
77
+ onSelect?: () => void;
78
+ }
79
+ interface IListingMarkerProps {
80
+ point: MapPoint<unknown>;
81
+ }
82
+ interface IListingPopupProps {
83
+ entity: unknown;
84
+ onClose?: () => void;
85
+ }
86
+ interface IListingSidebarProps {
87
+ children?: ReactNode;
88
+ }
89
+ interface IListingFilterPanelProps {
90
+ children?: ReactNode;
91
+ }
92
+ interface IListingSearchProps {
93
+ value: string;
94
+ onChange(value: string): void;
95
+ placeholder?: string;
96
+ }
97
+ interface IListingEmptyProps {
98
+ }
99
+ interface IListingLoadingProps {
100
+ }
101
+ interface IListingResultHeaderProps {
102
+ count: number;
103
+ total?: number;
104
+ }
105
+ interface IListingToolbarProps {
106
+ children?: ReactNode;
107
+ }
108
+ interface IListingComponents {
109
+ Card: ComponentType<IListingCardProps>;
110
+ Marker: ComponentType<IListingMarkerProps>;
111
+ Popup: ComponentType<IListingPopupProps>;
112
+ Sidebar: ComponentType<IListingSidebarProps>;
113
+ FilterPanel: ComponentType<IListingFilterPanelProps>;
114
+ Search: ComponentType<IListingSearchProps>;
115
+ Empty: ComponentType<IListingEmptyProps>;
116
+ Loading: ComponentType<IListingLoadingProps>;
117
+ ResultHeader: ComponentType<IListingResultHeaderProps>;
118
+ Toolbar: ComponentType<IListingToolbarProps>;
119
+ }
120
+ /**
121
+ * Injection point for custom-component overrides. Every slot is optional —
122
+ * anything not provided falls back to the (unstyled) default. Mirrors
123
+ * `react-wizard-engine`'s `WizardComponentsProvider`: explicit per-slot
124
+ * `provided ?? defaults.X` merge, not a generic/reflective loop.
125
+ */
126
+ declare function ListingComponentsProvider(props: Partial<IListingComponents> & {
127
+ children: ReactNode;
128
+ }): react.JSX.Element;
129
+ declare function useListingComponents(): IListingComponents;
7
130
 
8
131
  type BottomNavView = 'list' | 'map';
9
132
  interface IBottomNavAction {
@@ -29,8 +152,8 @@ declare function BottomNav({ view, onViewChange }: IBottomNavProps): react.JSX.E
29
152
 
30
153
  interface IStyledListingLayoutProps {
31
154
  /**
32
- * Optional header search box, LIBRARY-wired (unlike `/shadcn`'s
33
- * consumer-managed `search`): name the `TFilters` field it drives via
155
+ * Optional header search box, LIBRARY-wired: name the `TFilters` field it
156
+ * drives via
34
157
  * `filterKey`, and the layout reads the current value from the engine's
35
158
  * filters and writes edits back with `applyFilters({ [filterKey]: value ||
36
159
  * undefined })`. Rendered in BOTH the desktop filter bar and the mobile
@@ -61,12 +184,11 @@ interface IStyledListingLayoutProps {
61
184
  className?: string;
62
185
  }
63
186
  /**
64
- * Full, responsive, Tailwind-free listing experience -- the `/styled`
65
- * counterpart to `/shadcn`'s `ListingLayout`, built from the same
187
+ * Full, responsive, Tailwind-free listing experience -- built from the
66
188
  * structure-only compound components (`~/react`) plus the injected
67
- * `Styled*` slot components, but with a richer mobile experience: a bottom
68
- * nav (`BottomNav`) and a bottom sheet (`BottomSheet`) for filters, instead
69
- * of `/shadcn`'s inline mobile toggle bar. Every class used here is one of
189
+ * `Styled*` slot components, with a rich mobile experience: a bottom
190
+ * nav (`BottomNav`) and a bottom sheet (`BottomSheet`) for filters. Every
191
+ * class used here is one of
70
192
  * the `.rle-*` layout classes added to `styles.css` alongside this file --
71
193
  * no Tailwind, no inline styles, no other stylesheet required.
72
194
  *
@@ -98,18 +220,17 @@ interface IStyledListingLayoutProps {
98
220
  * control already applies live via its own `onChange`, so there is nothing
99
221
  * left to commit).
100
222
  * - Fetches the first page itself on mount (`engine.applyFilters({})`) by
101
- * default, exactly like `/shadcn`'s `ListingLayout` -- pass `autoFetch={false}`
223
+ * default -- pass `autoFetch={false}`
102
224
  * to opt out and drive the first fetch yourself.
103
225
  */
104
226
  declare function StyledListingLayout({ search, toolbarEnd, mobileAction, autoFetch, hasMap, mapCenter, mapZoom, className, }: IStyledListingLayoutProps): react.JSX.Element;
105
227
 
106
228
  /**
107
- * Same two-shape `map` prop as `/shadcn`'s `ListingApp` (see that file's
108
- * `useResolvedMap` doc comment for why the `{ apiKey }` shorthand is resolved
109
- * via a dynamic `import()` rather than a static one -- the reasoning is
110
- * identical here). Re-declared rather than imported from `~/shadcn`: the two
111
- * styled adapters are SIBLINGS, not a hierarchy -- `/styled` never depends on
112
- * `/shadcn` (or vice versa), each is self-contained against `~/core`/`~/react`.
229
+ * Two-shape `map` prop: pass a ready `MapProvider`, or the `{ apiKey, mapId? }`
230
+ * shorthand. The shorthand is resolved via a DYNAMIC `import()` of
231
+ * `~/maps/google` (see `useResolvedMap` below) rather than a static one, so an
232
+ * app that never sets `map` doesn't pull `@googlemaps/js-api-loader` into its
233
+ * bundle.
113
234
  */
114
235
  type ListingAppMapProp = {
115
236
  provider: MapProvider;
@@ -133,7 +254,7 @@ interface ListingAppProps<TFilters> {
133
254
  * `withDataset` doc comment.
134
255
  */
135
256
  datasets: DatasetDefinition<any, TFilters>[];
136
- /** e.g. `withRentalFilters()`, or any `(reg) => { reg.add(...); }` callback -- forwarded verbatim to `withFilters`. */
257
+ /** A `(reg) => { reg.add(...); }` callback that registers your filters -- forwarded verbatim to `withFilters`. */
137
258
  filters?: (reg: FilterRegistry<TFilters>) => void;
138
259
  /** A ready `MapProvider`, or `{ apiKey, mapId? }` to build a `googleProvider` internally. Omit for no map (the styled layout shows a "Map unavailable" fallback). */
139
260
  map?: ListingAppMapProp;
@@ -177,9 +298,8 @@ interface ListingAppProps<TFilters> {
177
298
  className?: string;
178
299
  }
179
300
  /**
180
- * Turnkey, batteries-included, Tailwind-free entry point -- the `/styled`
181
- * counterpart to `/shadcn`'s `ListingApp`, and (per `src/index.ts`) the
182
- * package's MAIN-ENTRY default: `import { ListingApp } from
301
+ * Turnkey, batteries-included, Tailwind-free entry point -- and (per
302
+ * `src/index.ts`) the package's MAIN-ENTRY default: `import { ListingApp } from
183
303
  * 'react-listing-engine'` gives you this component. Pass datasets + filters +
184
304
  * a map + component overrides, and `ListingApp` composes
185
305
  * `composeListingProviders(...)`, `<ListingProvider>`, the `/styled` defaults,
@@ -200,8 +320,8 @@ interface ListingAppProps<TFilters> {
200
320
  * nesting would silently discard every un-overridden `/styled` default
201
321
  * instead of keeping it.
202
322
  *
203
- * URL SYNC IS EVENT-BASED, NOT INTERNAL: unlike `/shadcn`'s `ListingApp`,
204
- * this component takes no `urlSync` prop and never constructs/starts a
323
+ * URL SYNC IS EVENT-BASED, NOT INTERNAL: this component takes no `urlSync`
324
+ * prop and never constructs/starts a
205
325
  * `UrlSyncController` -- it never touches `window.history`. Instead it
206
326
  * accepts `initialFilters` (hydrate FROM the consumer's URL) and emits
207
327
  * `onFiltersChange` (write TO the consumer's URL/router) -- see both props'
@@ -212,4 +332,4 @@ interface ListingAppProps<TFilters> {
212
332
  */
213
333
  declare function ListingApp<TEntity, TFilters>(props: ListingAppProps<TFilters>): react.JSX.Element | null;
214
334
 
215
- export { BottomNav as B, type IBottomNavAction as I, ListingApp as L, StyledListingLayout as S, type ListingAppProps as a, type BottomNavView as b, type IBottomNavProps as c, type IStyledListingLayoutProps as d, type ListingAppMapProp as e };
335
+ export { BottomNav as B, type ClusterOptions as C, type DatasetDefinition as D, FilterRegistry as F, type IListingConfigOptions as I, ListingApp as L, type MarkerRenderer as M, PaginationMode as P, StyledListingLayout as S, type IListingToolbarProps as a, type FilterControlProps as b, type FilterDefinition as c, type IListingCardProps as d, type IListingComponents as e, type IListingEmptyProps as f, type IListingFilterPanelProps as g, type IListingLoadingProps as h, type IListingMarkerProps as i, type IListingPopupProps as j, type IListingResultHeaderProps as k, type IListingSearchProps as l, type IListingSidebarProps as m, type ListingAppProps as n, ListingComponentsProvider as o, type BottomNavView as p, type IBottomNavAction as q, type IBottomNavProps as r, type IStyledListingLayoutProps as s, type ListingAppMapProp as t, useListingComponents as u };