react-listing-engine 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/LICENSE +21 -0
  3. package/README.md +161 -0
  4. package/dist/chunk-2T5PE5MB.js +2 -0
  5. package/dist/chunk-2VUHLHHX.cjs +2 -0
  6. package/dist/chunk-35KYEBAC.js +2 -0
  7. package/dist/chunk-5FBI2WIM.js +2 -0
  8. package/dist/chunk-5O36WI7H.cjs +2 -0
  9. package/dist/chunk-6PZHSHU3.js +2 -0
  10. package/dist/chunk-CHNUE46K.cjs +2 -0
  11. package/dist/chunk-LCQZIWBO.cjs +2 -0
  12. package/dist/chunk-N3OZ2HK2.cjs +2 -0
  13. package/dist/chunk-PFPHWJAA.js +2 -0
  14. package/dist/components-provider-CF0Mo0B8.d.cts +120 -0
  15. package/dist/components-provider-CjMxkxrP.d.ts +120 -0
  16. package/dist/entity-adapter.interface-BDgbSxhq.d.cts +33 -0
  17. package/dist/entity-adapter.interface-BDgbSxhq.d.ts +33 -0
  18. package/dist/index.cjs +2 -0
  19. package/dist/index.d.cts +674 -0
  20. package/dist/index.d.ts +674 -0
  21. package/dist/index.js +2 -0
  22. package/dist/listing-app-De6OqpUC.d.ts +199 -0
  23. package/dist/listing-app-pKMQBuQI.d.cts +199 -0
  24. package/dist/listing-config-options.interface-ZJYY_ZvR.d.cts +12 -0
  25. package/dist/listing-config-options.interface-ZJYY_ZvR.d.ts +12 -0
  26. package/dist/map-provider.interface-BMnwW3ob.d.cts +37 -0
  27. package/dist/map-provider.interface-BxexMT3X.d.ts +37 -0
  28. package/dist/maps/google/index.cjs +2 -0
  29. package/dist/maps/google/index.d.cts +39 -0
  30. package/dist/maps/google/index.d.ts +39 -0
  31. package/dist/maps/google/index.js +2 -0
  32. package/dist/presets/rental/index.cjs +2 -0
  33. package/dist/presets/rental/index.d.cts +266 -0
  34. package/dist/presets/rental/index.d.ts +266 -0
  35. package/dist/presets/rental/index.js +2 -0
  36. package/dist/shadcn/index.cjs +2 -0
  37. package/dist/shadcn/index.d.cts +261 -0
  38. package/dist/shadcn/index.d.ts +261 -0
  39. package/dist/shadcn/index.js +2 -0
  40. package/dist/styled/index.cjs +2 -0
  41. package/dist/styled/index.d.cts +123 -0
  42. package/dist/styled/index.d.ts +123 -0
  43. package/dist/styled/index.js +2 -0
  44. package/dist/styles.css +972 -0
  45. package/dist/testing/index.cjs +2 -0
  46. package/dist/testing/index.d.cts +51 -0
  47. package/dist/testing/index.d.ts +51 -0
  48. package/dist/testing/index.js +2 -0
  49. package/dist/url-sync.controller-CsU_QxoS.d.cts +89 -0
  50. package/dist/url-sync.controller-DX67JivW.d.ts +89 -0
  51. package/package.json +143 -0
@@ -0,0 +1,261 @@
1
+ import * as react from 'react';
2
+ import { ReactNode } from 'react';
3
+ import { 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, I as IListingToolbarProps, D as DatasetDefinition, F as FilterRegistry } from '../components-provider-CF0Mo0B8.cjs';
4
+ import { L as LatLng } from '../entity-adapter.interface-BDgbSxhq.cjs';
5
+ import { M as MapProvider } from '../map-provider.interface-BMnwW3ob.cjs';
6
+ import { I as IListingConfigOptions } from '../listing-config-options.interface-ZJYY_ZvR.cjs';
7
+ import { U as UrlSyncController } from '../url-sync.controller-CsU_QxoS.cjs';
8
+ import { ClassValue } from 'clsx';
9
+
10
+ /**
11
+ * Convenience wrapper around `ListingComponentsProvider` that wires in every
12
+ * package-shipped `Default*` component (via `shadcnDefaultComponents`, the
13
+ * shared source of truth also used by `ListingApp`'s merge). Use this if you
14
+ * want the styled adapter out of the box; use `ListingComponentsProvider`
15
+ * directly (with your own components for some or all slots) otherwise -- the
16
+ * two compose fine since `ListingComponentsProvider` falls back per-slot.
17
+ * Mirrors `react-wizard-engine`'s `WizardComponentsProviderWithDefaults`.
18
+ */
19
+ declare function ListingComponentsProviderWithDefaults({ children }: {
20
+ children: ReactNode;
21
+ }): react.JSX.Element;
22
+
23
+ /**
24
+ * Default styled `Card` slot. Renders an optional image, title, subtitle,
25
+ * price and badge from a plain view-model item, and doubles as the
26
+ * clickable/selectable surface (`onSelect`) -- when `onSelect` is provided
27
+ * the card is a `button` rather than a `div` + click handler so it is
28
+ * keyboard operable and announces as a toggle (`aria-pressed`) for free.
29
+ * When `onSelect` is absent (display-only usage) it renders as a
30
+ * non-interactive `<article>` with the same visual classes, minus the
31
+ * button/focus/aria-pressed semantics -- so a purely presentational card
32
+ * doesn't add a no-op tab stop.
33
+ */
34
+ declare function DefaultCard({ item, selected, onSelect }: IListingCardProps): react.JSX.Element;
35
+
36
+ /**
37
+ * Every `/shadcn` styled default, keyed by slot -- the single source of truth
38
+ * both `ListingComponentsProviderWithDefaults` (spreads it verbatim) and
39
+ * `ListingApp` (spreads a `components` override OVER it) build on.
40
+ *
41
+ * Kept as a plain object, not JSX, so a caller can merge it with
42
+ * `{ ...shadcnDefaultComponents, ...overrides }` and hand the result to ONE
43
+ * `ListingComponentsProvider`. This matters because `ListingComponentsProvider`
44
+ * merges `provided ?? ITS OWN private, UNSTYLED fallbacks` per slot -- it does
45
+ * not read the parent context (see `src/react/components-provider.tsx`).
46
+ * Nesting a `ListingComponentsProvider` (with only the overrides) INSIDE a
47
+ * `ListingComponentsProviderWithDefaults` would therefore silently reset
48
+ * every un-overridden slot back to the bare fallback instead of the shadcn
49
+ * default -- exactly the bug this object exists to avoid.
50
+ */
51
+ declare const shadcnDefaultComponents: IListingComponents;
52
+
53
+ /** Default styled `Empty` slot: a centered empty state with an icon, heading and hint. */
54
+ declare function DefaultEmpty(_props: IListingEmptyProps): react.JSX.Element;
55
+
56
+ /** Default styled `FilterPanel` slot: stacks one filter control per row inside `Sidebar`. */
57
+ declare function DefaultFilterPanel({ children }: IListingFilterPanelProps): react.JSX.Element;
58
+
59
+ /** Default styled `Loading` slot: a shimmering skeleton list, announced via `role="status"`. */
60
+ declare function DefaultLoading(_props: IListingLoadingProps): react.JSX.Element;
61
+
62
+ /** Default styled `Marker` slot: a small price pill for a map point. */
63
+ declare function DefaultMarker({ point }: IListingMarkerProps): react.JSX.Element;
64
+
65
+ /**
66
+ * Default styled `Popup` slot: a small card with an accessible close button.
67
+ * `role="group"` + `aria-label` (rather than `role="dialog"`) since this is a
68
+ * non-modal, non-focus-trapped popup anchored to a map marker -- `dialog`
69
+ * without modality/focus management would misrepresent it to AT users.
70
+ */
71
+ declare function DefaultPopup({ entity, onClose }: IListingPopupProps): react.JSX.Element;
72
+
73
+ /** Default styled `ResultHeader` slot: `"{count} results"`, or `"{count} of {total} results"` when a distinct total is known. */
74
+ declare function DefaultResultHeader({ count, total }: IListingResultHeaderProps): react.JSX.Element;
75
+
76
+ /** Default styled `Search` slot: a plain styled text input. */
77
+ declare function DefaultSearch({ value, onChange, placeholder }: IListingSearchProps): react.JSX.Element;
78
+
79
+ /**
80
+ * Default styled `Sidebar` slot: the outer chrome for the filters column in
81
+ * `ListingLayout`. Full width and unbordered on mobile (stacks above the
82
+ * results in normal document flow); becomes a fixed-width bordered rail from
83
+ * `md` up.
84
+ */
85
+ declare function DefaultSidebar({ children }: IListingSidebarProps): react.JSX.Element;
86
+
87
+ /** Default styled `Toolbar` slot: a bordered bar wrapping arbitrary children. */
88
+ declare function DefaultToolbar({ children }: IListingToolbarProps): react.JSX.Element;
89
+
90
+ interface IListingLayoutProps {
91
+ /**
92
+ * Optional search box, wired by the CONSUMER into their own `TFilters`
93
+ * shape. `ListingLayout` is filters-shape-erased (same reasoning as the
94
+ * engine itself -- see `ListingEngineOptions`'s docstring) so it cannot
95
+ * derive a generic "search" filter on its own; when omitted, no search box
96
+ * is rendered at all. Documented, deliberate scope: wiring a named
97
+ * "search" filter convention end-to-end is a future enhancement.
98
+ */
99
+ search?: {
100
+ value: string;
101
+ onChange: (value: string) => void;
102
+ placeholder?: string;
103
+ };
104
+ className?: string;
105
+ /** Extra content rendered at the end of the filter bar, alongside `ListingResultHeader` (e.g. a sort control). */
106
+ toolbarEnd?: ReactNode;
107
+ /**
108
+ * Whether `ListingLayout` fetches the first page itself on mount
109
+ * (`engine.applyFilters({})`). Defaults to `true` (batteries-included).
110
+ * Pass `false` to defer the initial fetch to the caller -- e.g. a
111
+ * search-before-results flow, or when `urlSync` hydrates filters from the
112
+ * URL and should drive the first fetch instead of racing it.
113
+ */
114
+ autoFetch?: boolean;
115
+ /**
116
+ * Forwarded verbatim to `<ListingMap center={mapCenter} />`. Omit to get
117
+ * `ListingMap`'s turnkey auto-fit default (frames the map to its own data
118
+ * once it loads) -- passing `mapCenter` opts OUT of auto-fit entirely, on
119
+ * the theory that an explicit initial view is a deliberate choice
120
+ * (see `ListingMap`'s doc comment's "Auto-fit" section).
121
+ */
122
+ mapCenter?: LatLng;
123
+ /** Forwarded verbatim to `<ListingMap zoom={mapZoom} />`. See `mapCenter`. */
124
+ mapZoom?: number;
125
+ }
126
+ /**
127
+ * Full, responsive default listing experience, matching the "top filter bar
128
+ * + list-left/map-right split" pattern of a typical `/find` real-estate
129
+ * search page: a sticky horizontal filter bar (search + filter groups +
130
+ * result count), then below it a split -- a scrollable card grid on the left
131
+ * and a full-height map on the right. Composed entirely from the
132
+ * structure-only compound components in `~/react` plus the injected slot
133
+ * components (via `useListingComponents()` for `Search`, and implicitly
134
+ * through each compound component for `Card`/`Empty`/`Loading`/etc.) -- this
135
+ * file adds layout/chrome only, no new business logic.
136
+ *
137
+ * Layout choices (documented, not the only valid ones):
138
+ * - FILTER BAR (`data-slot="listing-layout-filter-bar"`): `sticky top-0`,
139
+ * `border-b`/`bg-background`, and a `flex flex-wrap items-end gap-3` row
140
+ * containing the injected `Search` (when `search` is passed),
141
+ * `<ListingFilters>` (given the same horizontal row className plus a
142
+ * `min-w-0` `groupClassName` so individual groups can shrink instead of
143
+ * forcing overflow), and a trailing `ml-auto` cluster with
144
+ * `<ListingResultHeader>` + `toolbarEnd`. `flex-wrap` is what makes this
145
+ * gracefully reflow on narrow widths -- groups drop to new lines instead
146
+ * of overflowing or requiring a separate mobile-only layout.
147
+ * - SPLIT (`data-slot="listing-layout-split"`): a single CSS grid,
148
+ * `md:grid-cols-[minmax(340px,42%)_1fr]` from `md` up (list column floors
149
+ * at 340px, caps at 42% of the split's width; map takes the rest). Below
150
+ * `md` there is no grid -- just two full-width panels, and exactly one is
151
+ * visible at a time (see the mobile toggle below).
152
+ * - LIST region (`data-slot="listing-layout-list"`): `overflow-y-auto`, its
153
+ * own scroll container so browsing the list never requires scrolling the
154
+ * map out of view. Holds `<ListingList>` (an auto-fill card grid) and
155
+ * `<ListingPagination>`.
156
+ * - MAP region (`data-slot="listing-layout-map"`): fills the split's full
157
+ * height via the grid's default stretch alignment (no explicit height
158
+ * needed), plus `md:sticky md:top-0` so that if a consuming app ever lets
159
+ * `ListingLayout` sit inside a naturally document-scrolling page (rather
160
+ * than the fixed-height shell this component defaults to via
161
+ * `h-full min-h-0`), the map still pins in place while the list scrolls
162
+ * past -- inert (but harmless) in the default fixed-height composition,
163
+ * where there is nothing above the split to scroll past in the first
164
+ * place. Renders `<ListingMap>` with a default centered fallback message
165
+ * (`MAP_FALLBACK`) for when no `MapProvider` is configured, so the pane
166
+ * never looks broken/blank.
167
+ * - MOBILE LIST/MAP TOGGLE (`data-slot="listing-layout-mobile-toggle"`,
168
+ * `md:hidden`): a small two-button segmented control, local `useState`
169
+ * (`mobileView`), defaulting to `'list'`. Both the list and map regions
170
+ * stay mounted at all times (never remounted on toggle -- that would
171
+ * re-trigger `ListingList`'s/`ListingMap`'s own mount effects for no
172
+ * reason); only their visibility flips via `hidden md:block` /
173
+ * `block md:block`, i.e. the toggle only ever matters below `md` -- at
174
+ * `md` and up both regions are always visible side by side and the toggle
175
+ * control itself is hidden.
176
+ * - Fetches the first page itself on mount (`engine.applyFilters({})`) by
177
+ * default: none of the structure-only `~/react` compound components do
178
+ * this (they are deliberately side-effect-free), so as the
179
+ * batteries-included "full experience" entry point, `ListingLayout` is the
180
+ * natural, single owner of that one bootstrapping side effect. Pass
181
+ * `autoFetch={false}` to opt out and drive the first fetch yourself (e.g.
182
+ * search-before-results, or when `urlSync` hydrates filters from the URL).
183
+ */
184
+ declare function ListingLayout({ search, className, toolbarEnd, autoFetch, mapCenter, mapZoom, }: IListingLayoutProps): react.JSX.Element;
185
+
186
+ /**
187
+ * `ListingApp.map` accepts either a ready-made `MapProvider` (any
188
+ * implementation -- Google, a fake, a future provider) or, as a convenience,
189
+ * a bare Google Maps API key. See `useResolvedMap`'s doc comment for why the
190
+ * key shorthand is resolved via a dynamic `import()` rather than a static one.
191
+ *
192
+ * Both shapes optionally carry `center`/`zoom` -- the initial view, forwarded
193
+ * through `ListingLayout`'s `mapCenter`/`mapZoom` straight into
194
+ * `ListingMap`'s own `center`/`zoom` props. Omit them to get `ListingMap`'s
195
+ * turnkey auto-fit default instead (see that component's doc comment);
196
+ * supplying `center` opts out of auto-fit entirely.
197
+ */
198
+ type ListingAppMapProp = {
199
+ provider: MapProvider;
200
+ center?: LatLng;
201
+ zoom?: number;
202
+ } | {
203
+ apiKey: string;
204
+ mapId?: string;
205
+ center?: LatLng;
206
+ zoom?: number;
207
+ };
208
+ interface ListingAppProps<TFilters> {
209
+ /**
210
+ * One or more marker-layer datasets; the FIRST entry is the primary
211
+ * dataset (drives the results list + pagination) -- same "insertion order"
212
+ * rule `composeListingProviders`/`withDataset` already follow. Entity-erased
213
+ * (`any`, not `TEntity`) for the same reason `DatasetRegistry<unknown,
214
+ * TFilters>` is: one array can legitimately hold heterogeneous layers (a
215
+ * properties dataset and a businesses dataset have different entity types)
216
+ * -- see `compose-listing-providers.ts`'s `withDataset` doc comment.
217
+ */
218
+ datasets: DatasetDefinition<any, TFilters>[];
219
+ /** e.g. `withRentalFilters()`, or any `(reg) => { reg.add(...); }` callback -- forwarded verbatim to `withFilters`. */
220
+ filters?: (reg: FilterRegistry<TFilters>) => void;
221
+ /** A ready `MapProvider`, or `{ apiKey, mapId? }` to build a `googleProvider` internally. Omit for no map (the styled layout shows a "Map unavailable" fallback). */
222
+ map?: ListingAppMapProp;
223
+ /** Slot overrides, merged OVER the shadcn styled defaults -- see this file's doc comment for how the merge works. */
224
+ components?: Partial<IListingComponents>;
225
+ /** A `UrlSyncController<TFilters>` (e.g. `rentalUrlSync()`), or `true`. `true` is a documented no-op: the library is filters-shape-erased and cannot generically derive a `TFilters <-> QueryParams` mapping, which is exactly why domain presets (like `rentalUrlSync`) exist to build a real controller. */
226
+ urlSync?: UrlSyncController<TFilters> | boolean;
227
+ initialFilters?: TFilters;
228
+ config?: Partial<IListingConfigOptions>;
229
+ className?: string;
230
+ search?: IListingLayoutProps['search'];
231
+ autoFetch?: boolean;
232
+ }
233
+ /**
234
+ * Turnkey, batteries-included entry point: pass datasets + filters + a map +
235
+ * component overrides + URL sync, and `ListingApp` composes
236
+ * `composeListingProviders(...)`, `<ListingProvider>`, the styled `/shadcn`
237
+ * defaults, and `<ListingLayout>` for you. Equivalent to (and internally
238
+ * built from) the lower-level primitives every other `/shadcn` example wires
239
+ * by hand -- reach for those directly when you need something `ListingApp`
240
+ * doesn't expose (e.g. multiple `<ListingLayout>`s sharing one engine).
241
+ *
242
+ * `TEntity` still can't be inferred from these props (`datasets` narrows it,
243
+ * but a multi-dataset array widens back to the union/`unknown` in practice)
244
+ * -- annotate the call site when entity-level typing matters, exactly like
245
+ * `<ListingProvider<TEntity, TFilters>>` itself.
246
+ *
247
+ * COMPONENTS MERGE: `components` overrides are applied ON TOP of the shadcn
248
+ * styled defaults via ONE explicit `{ ...shadcnDefaultComponents, ...components }`
249
+ * object, passed to a single `<ListingComponentsProvider>` -- never as a
250
+ * nested `<ListingComponentsProvider>` inside `<ListingComponentsProviderWithDefaults>`.
251
+ * `ListingComponentsProvider` merges `provided ?? ITS OWN private, unstyled
252
+ * fallbacks` per slot (it does not read the parent context -- see
253
+ * `src/react/components-provider.tsx`), so nesting would silently discard
254
+ * every un-overridden shadcn default instead of keeping it.
255
+ */
256
+ declare function ListingApp<TEntity, TFilters>(props: ListingAppProps<TFilters>): react.JSX.Element | null;
257
+
258
+ /** Merges class-name fragments, letting `tailwind-merge` resolve conflicting Tailwind utilities (last one wins). Mirrors `react-wizard-engine`'s `~/utils/cn`. */
259
+ declare function cn(...inputs: ClassValue[]): string;
260
+
261
+ export { DefaultCard, DefaultEmpty, DefaultFilterPanel, DefaultLoading, DefaultMarker, DefaultPopup, DefaultResultHeader, DefaultSearch, DefaultSidebar, DefaultToolbar, type IListingLayoutProps, ListingApp, type ListingAppMapProp, type ListingAppProps, ListingComponentsProviderWithDefaults, ListingLayout, cn, shadcnDefaultComponents };
@@ -0,0 +1,261 @@
1
+ import * as react from 'react';
2
+ import { ReactNode } from 'react';
3
+ import { 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, I as IListingToolbarProps, D as DatasetDefinition, F as FilterRegistry } from '../components-provider-CjMxkxrP.js';
4
+ import { L as LatLng } from '../entity-adapter.interface-BDgbSxhq.js';
5
+ import { M as MapProvider } from '../map-provider.interface-BxexMT3X.js';
6
+ import { I as IListingConfigOptions } from '../listing-config-options.interface-ZJYY_ZvR.js';
7
+ import { U as UrlSyncController } from '../url-sync.controller-DX67JivW.js';
8
+ import { ClassValue } from 'clsx';
9
+
10
+ /**
11
+ * Convenience wrapper around `ListingComponentsProvider` that wires in every
12
+ * package-shipped `Default*` component (via `shadcnDefaultComponents`, the
13
+ * shared source of truth also used by `ListingApp`'s merge). Use this if you
14
+ * want the styled adapter out of the box; use `ListingComponentsProvider`
15
+ * directly (with your own components for some or all slots) otherwise -- the
16
+ * two compose fine since `ListingComponentsProvider` falls back per-slot.
17
+ * Mirrors `react-wizard-engine`'s `WizardComponentsProviderWithDefaults`.
18
+ */
19
+ declare function ListingComponentsProviderWithDefaults({ children }: {
20
+ children: ReactNode;
21
+ }): react.JSX.Element;
22
+
23
+ /**
24
+ * Default styled `Card` slot. Renders an optional image, title, subtitle,
25
+ * price and badge from a plain view-model item, and doubles as the
26
+ * clickable/selectable surface (`onSelect`) -- when `onSelect` is provided
27
+ * the card is a `button` rather than a `div` + click handler so it is
28
+ * keyboard operable and announces as a toggle (`aria-pressed`) for free.
29
+ * When `onSelect` is absent (display-only usage) it renders as a
30
+ * non-interactive `<article>` with the same visual classes, minus the
31
+ * button/focus/aria-pressed semantics -- so a purely presentational card
32
+ * doesn't add a no-op tab stop.
33
+ */
34
+ declare function DefaultCard({ item, selected, onSelect }: IListingCardProps): react.JSX.Element;
35
+
36
+ /**
37
+ * Every `/shadcn` styled default, keyed by slot -- the single source of truth
38
+ * both `ListingComponentsProviderWithDefaults` (spreads it verbatim) and
39
+ * `ListingApp` (spreads a `components` override OVER it) build on.
40
+ *
41
+ * Kept as a plain object, not JSX, so a caller can merge it with
42
+ * `{ ...shadcnDefaultComponents, ...overrides }` and hand the result to ONE
43
+ * `ListingComponentsProvider`. This matters because `ListingComponentsProvider`
44
+ * merges `provided ?? ITS OWN private, UNSTYLED fallbacks` per slot -- it does
45
+ * not read the parent context (see `src/react/components-provider.tsx`).
46
+ * Nesting a `ListingComponentsProvider` (with only the overrides) INSIDE a
47
+ * `ListingComponentsProviderWithDefaults` would therefore silently reset
48
+ * every un-overridden slot back to the bare fallback instead of the shadcn
49
+ * default -- exactly the bug this object exists to avoid.
50
+ */
51
+ declare const shadcnDefaultComponents: IListingComponents;
52
+
53
+ /** Default styled `Empty` slot: a centered empty state with an icon, heading and hint. */
54
+ declare function DefaultEmpty(_props: IListingEmptyProps): react.JSX.Element;
55
+
56
+ /** Default styled `FilterPanel` slot: stacks one filter control per row inside `Sidebar`. */
57
+ declare function DefaultFilterPanel({ children }: IListingFilterPanelProps): react.JSX.Element;
58
+
59
+ /** Default styled `Loading` slot: a shimmering skeleton list, announced via `role="status"`. */
60
+ declare function DefaultLoading(_props: IListingLoadingProps): react.JSX.Element;
61
+
62
+ /** Default styled `Marker` slot: a small price pill for a map point. */
63
+ declare function DefaultMarker({ point }: IListingMarkerProps): react.JSX.Element;
64
+
65
+ /**
66
+ * Default styled `Popup` slot: a small card with an accessible close button.
67
+ * `role="group"` + `aria-label` (rather than `role="dialog"`) since this is a
68
+ * non-modal, non-focus-trapped popup anchored to a map marker -- `dialog`
69
+ * without modality/focus management would misrepresent it to AT users.
70
+ */
71
+ declare function DefaultPopup({ entity, onClose }: IListingPopupProps): react.JSX.Element;
72
+
73
+ /** Default styled `ResultHeader` slot: `"{count} results"`, or `"{count} of {total} results"` when a distinct total is known. */
74
+ declare function DefaultResultHeader({ count, total }: IListingResultHeaderProps): react.JSX.Element;
75
+
76
+ /** Default styled `Search` slot: a plain styled text input. */
77
+ declare function DefaultSearch({ value, onChange, placeholder }: IListingSearchProps): react.JSX.Element;
78
+
79
+ /**
80
+ * Default styled `Sidebar` slot: the outer chrome for the filters column in
81
+ * `ListingLayout`. Full width and unbordered on mobile (stacks above the
82
+ * results in normal document flow); becomes a fixed-width bordered rail from
83
+ * `md` up.
84
+ */
85
+ declare function DefaultSidebar({ children }: IListingSidebarProps): react.JSX.Element;
86
+
87
+ /** Default styled `Toolbar` slot: a bordered bar wrapping arbitrary children. */
88
+ declare function DefaultToolbar({ children }: IListingToolbarProps): react.JSX.Element;
89
+
90
+ interface IListingLayoutProps {
91
+ /**
92
+ * Optional search box, wired by the CONSUMER into their own `TFilters`
93
+ * shape. `ListingLayout` is filters-shape-erased (same reasoning as the
94
+ * engine itself -- see `ListingEngineOptions`'s docstring) so it cannot
95
+ * derive a generic "search" filter on its own; when omitted, no search box
96
+ * is rendered at all. Documented, deliberate scope: wiring a named
97
+ * "search" filter convention end-to-end is a future enhancement.
98
+ */
99
+ search?: {
100
+ value: string;
101
+ onChange: (value: string) => void;
102
+ placeholder?: string;
103
+ };
104
+ className?: string;
105
+ /** Extra content rendered at the end of the filter bar, alongside `ListingResultHeader` (e.g. a sort control). */
106
+ toolbarEnd?: ReactNode;
107
+ /**
108
+ * Whether `ListingLayout` fetches the first page itself on mount
109
+ * (`engine.applyFilters({})`). Defaults to `true` (batteries-included).
110
+ * Pass `false` to defer the initial fetch to the caller -- e.g. a
111
+ * search-before-results flow, or when `urlSync` hydrates filters from the
112
+ * URL and should drive the first fetch instead of racing it.
113
+ */
114
+ autoFetch?: boolean;
115
+ /**
116
+ * Forwarded verbatim to `<ListingMap center={mapCenter} />`. Omit to get
117
+ * `ListingMap`'s turnkey auto-fit default (frames the map to its own data
118
+ * once it loads) -- passing `mapCenter` opts OUT of auto-fit entirely, on
119
+ * the theory that an explicit initial view is a deliberate choice
120
+ * (see `ListingMap`'s doc comment's "Auto-fit" section).
121
+ */
122
+ mapCenter?: LatLng;
123
+ /** Forwarded verbatim to `<ListingMap zoom={mapZoom} />`. See `mapCenter`. */
124
+ mapZoom?: number;
125
+ }
126
+ /**
127
+ * Full, responsive default listing experience, matching the "top filter bar
128
+ * + list-left/map-right split" pattern of a typical `/find` real-estate
129
+ * search page: a sticky horizontal filter bar (search + filter groups +
130
+ * result count), then below it a split -- a scrollable card grid on the left
131
+ * and a full-height map on the right. Composed entirely from the
132
+ * structure-only compound components in `~/react` plus the injected slot
133
+ * components (via `useListingComponents()` for `Search`, and implicitly
134
+ * through each compound component for `Card`/`Empty`/`Loading`/etc.) -- this
135
+ * file adds layout/chrome only, no new business logic.
136
+ *
137
+ * Layout choices (documented, not the only valid ones):
138
+ * - FILTER BAR (`data-slot="listing-layout-filter-bar"`): `sticky top-0`,
139
+ * `border-b`/`bg-background`, and a `flex flex-wrap items-end gap-3` row
140
+ * containing the injected `Search` (when `search` is passed),
141
+ * `<ListingFilters>` (given the same horizontal row className plus a
142
+ * `min-w-0` `groupClassName` so individual groups can shrink instead of
143
+ * forcing overflow), and a trailing `ml-auto` cluster with
144
+ * `<ListingResultHeader>` + `toolbarEnd`. `flex-wrap` is what makes this
145
+ * gracefully reflow on narrow widths -- groups drop to new lines instead
146
+ * of overflowing or requiring a separate mobile-only layout.
147
+ * - SPLIT (`data-slot="listing-layout-split"`): a single CSS grid,
148
+ * `md:grid-cols-[minmax(340px,42%)_1fr]` from `md` up (list column floors
149
+ * at 340px, caps at 42% of the split's width; map takes the rest). Below
150
+ * `md` there is no grid -- just two full-width panels, and exactly one is
151
+ * visible at a time (see the mobile toggle below).
152
+ * - LIST region (`data-slot="listing-layout-list"`): `overflow-y-auto`, its
153
+ * own scroll container so browsing the list never requires scrolling the
154
+ * map out of view. Holds `<ListingList>` (an auto-fill card grid) and
155
+ * `<ListingPagination>`.
156
+ * - MAP region (`data-slot="listing-layout-map"`): fills the split's full
157
+ * height via the grid's default stretch alignment (no explicit height
158
+ * needed), plus `md:sticky md:top-0` so that if a consuming app ever lets
159
+ * `ListingLayout` sit inside a naturally document-scrolling page (rather
160
+ * than the fixed-height shell this component defaults to via
161
+ * `h-full min-h-0`), the map still pins in place while the list scrolls
162
+ * past -- inert (but harmless) in the default fixed-height composition,
163
+ * where there is nothing above the split to scroll past in the first
164
+ * place. Renders `<ListingMap>` with a default centered fallback message
165
+ * (`MAP_FALLBACK`) for when no `MapProvider` is configured, so the pane
166
+ * never looks broken/blank.
167
+ * - MOBILE LIST/MAP TOGGLE (`data-slot="listing-layout-mobile-toggle"`,
168
+ * `md:hidden`): a small two-button segmented control, local `useState`
169
+ * (`mobileView`), defaulting to `'list'`. Both the list and map regions
170
+ * stay mounted at all times (never remounted on toggle -- that would
171
+ * re-trigger `ListingList`'s/`ListingMap`'s own mount effects for no
172
+ * reason); only their visibility flips via `hidden md:block` /
173
+ * `block md:block`, i.e. the toggle only ever matters below `md` -- at
174
+ * `md` and up both regions are always visible side by side and the toggle
175
+ * control itself is hidden.
176
+ * - Fetches the first page itself on mount (`engine.applyFilters({})`) by
177
+ * default: none of the structure-only `~/react` compound components do
178
+ * this (they are deliberately side-effect-free), so as the
179
+ * batteries-included "full experience" entry point, `ListingLayout` is the
180
+ * natural, single owner of that one bootstrapping side effect. Pass
181
+ * `autoFetch={false}` to opt out and drive the first fetch yourself (e.g.
182
+ * search-before-results, or when `urlSync` hydrates filters from the URL).
183
+ */
184
+ declare function ListingLayout({ search, className, toolbarEnd, autoFetch, mapCenter, mapZoom, }: IListingLayoutProps): react.JSX.Element;
185
+
186
+ /**
187
+ * `ListingApp.map` accepts either a ready-made `MapProvider` (any
188
+ * implementation -- Google, a fake, a future provider) or, as a convenience,
189
+ * a bare Google Maps API key. See `useResolvedMap`'s doc comment for why the
190
+ * key shorthand is resolved via a dynamic `import()` rather than a static one.
191
+ *
192
+ * Both shapes optionally carry `center`/`zoom` -- the initial view, forwarded
193
+ * through `ListingLayout`'s `mapCenter`/`mapZoom` straight into
194
+ * `ListingMap`'s own `center`/`zoom` props. Omit them to get `ListingMap`'s
195
+ * turnkey auto-fit default instead (see that component's doc comment);
196
+ * supplying `center` opts out of auto-fit entirely.
197
+ */
198
+ type ListingAppMapProp = {
199
+ provider: MapProvider;
200
+ center?: LatLng;
201
+ zoom?: number;
202
+ } | {
203
+ apiKey: string;
204
+ mapId?: string;
205
+ center?: LatLng;
206
+ zoom?: number;
207
+ };
208
+ interface ListingAppProps<TFilters> {
209
+ /**
210
+ * One or more marker-layer datasets; the FIRST entry is the primary
211
+ * dataset (drives the results list + pagination) -- same "insertion order"
212
+ * rule `composeListingProviders`/`withDataset` already follow. Entity-erased
213
+ * (`any`, not `TEntity`) for the same reason `DatasetRegistry<unknown,
214
+ * TFilters>` is: one array can legitimately hold heterogeneous layers (a
215
+ * properties dataset and a businesses dataset have different entity types)
216
+ * -- see `compose-listing-providers.ts`'s `withDataset` doc comment.
217
+ */
218
+ datasets: DatasetDefinition<any, TFilters>[];
219
+ /** e.g. `withRentalFilters()`, or any `(reg) => { reg.add(...); }` callback -- forwarded verbatim to `withFilters`. */
220
+ filters?: (reg: FilterRegistry<TFilters>) => void;
221
+ /** A ready `MapProvider`, or `{ apiKey, mapId? }` to build a `googleProvider` internally. Omit for no map (the styled layout shows a "Map unavailable" fallback). */
222
+ map?: ListingAppMapProp;
223
+ /** Slot overrides, merged OVER the shadcn styled defaults -- see this file's doc comment for how the merge works. */
224
+ components?: Partial<IListingComponents>;
225
+ /** A `UrlSyncController<TFilters>` (e.g. `rentalUrlSync()`), or `true`. `true` is a documented no-op: the library is filters-shape-erased and cannot generically derive a `TFilters <-> QueryParams` mapping, which is exactly why domain presets (like `rentalUrlSync`) exist to build a real controller. */
226
+ urlSync?: UrlSyncController<TFilters> | boolean;
227
+ initialFilters?: TFilters;
228
+ config?: Partial<IListingConfigOptions>;
229
+ className?: string;
230
+ search?: IListingLayoutProps['search'];
231
+ autoFetch?: boolean;
232
+ }
233
+ /**
234
+ * Turnkey, batteries-included entry point: pass datasets + filters + a map +
235
+ * component overrides + URL sync, and `ListingApp` composes
236
+ * `composeListingProviders(...)`, `<ListingProvider>`, the styled `/shadcn`
237
+ * defaults, and `<ListingLayout>` for you. Equivalent to (and internally
238
+ * built from) the lower-level primitives every other `/shadcn` example wires
239
+ * by hand -- reach for those directly when you need something `ListingApp`
240
+ * doesn't expose (e.g. multiple `<ListingLayout>`s sharing one engine).
241
+ *
242
+ * `TEntity` still can't be inferred from these props (`datasets` narrows it,
243
+ * but a multi-dataset array widens back to the union/`unknown` in practice)
244
+ * -- annotate the call site when entity-level typing matters, exactly like
245
+ * `<ListingProvider<TEntity, TFilters>>` itself.
246
+ *
247
+ * COMPONENTS MERGE: `components` overrides are applied ON TOP of the shadcn
248
+ * styled defaults via ONE explicit `{ ...shadcnDefaultComponents, ...components }`
249
+ * object, passed to a single `<ListingComponentsProvider>` -- never as a
250
+ * nested `<ListingComponentsProvider>` inside `<ListingComponentsProviderWithDefaults>`.
251
+ * `ListingComponentsProvider` merges `provided ?? ITS OWN private, unstyled
252
+ * fallbacks` per slot (it does not read the parent context -- see
253
+ * `src/react/components-provider.tsx`), so nesting would silently discard
254
+ * every un-overridden shadcn default instead of keeping it.
255
+ */
256
+ declare function ListingApp<TEntity, TFilters>(props: ListingAppProps<TFilters>): react.JSX.Element | null;
257
+
258
+ /** Merges class-name fragments, letting `tailwind-merge` resolve conflicting Tailwind utilities (last one wins). Mirrors `react-wizard-engine`'s `~/utils/cn`. */
259
+ declare function cn(...inputs: ClassValue[]): string;
260
+
261
+ export { DefaultCard, DefaultEmpty, DefaultFilterPanel, DefaultLoading, DefaultMarker, DefaultPopup, DefaultResultHeader, DefaultSearch, DefaultSidebar, DefaultToolbar, type IListingLayoutProps, ListingApp, type ListingAppMapProp, type ListingAppProps, ListingComponentsProviderWithDefaults, ListingLayout, cn, shadcnDefaultComponents };
@@ -0,0 +1,2 @@
1
+ "use client";
2
+ import{A as X,B as Y,h as U,i as H,j as _,k as O,l as W,m as z,n as B,p as v,q as $,s as Z,v as G,x as q,y as J,z as Q}from"../chunk-PFPHWJAA.js";import{a as s}from"../chunk-6PZHSHU3.js";import{a as K}from"../chunk-35KYEBAC.js";import{Fragment as se,jsx as m,jsxs as N}from"react/jsx-runtime";function oe(e){return typeof e!="number"?e:new Intl.NumberFormat("en-US",{style:"currency",currency:"USD",maximumFractionDigits:0}).format(e)}function w({item:e,selected:i,onSelect:t}){let r=e??{},l=s("flex w-full flex-col overflow-hidden rounded-lg border bg-card text-left text-card-foreground shadow-sm","motion-safe:transition-shadow",t&&"hover:shadow-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",i&&"ring-2 ring-ring"),a=N(se,{children:[r.imageUrl&&m("img",{src:r.imageUrl,alt:r.title??"",className:"aspect-video w-full rounded-t-lg object-cover"}),N("div",{className:"flex flex-1 flex-col gap-1 p-3",children:[N("div",{className:"flex items-start justify-between gap-2",children:[r.title&&m("span",{className:"font-medium",children:r.title}),r.badge&&m("span",{className:"shrink-0 rounded-full bg-muted px-2 py-0.5 text-xs font-medium text-muted-foreground",children:r.badge})]}),r.subtitle&&m("span",{className:"text-sm text-muted-foreground",children:r.subtitle}),r.price!=null&&m("span",{className:"mt-1 font-semibold tabular-nums",children:oe(r.price)})]})]});return t?m("button",{type:"button",onClick:t,"aria-pressed":i??!1,className:l,children:a}):m("article",{className:l,children:a})}import{jsx as L,jsxs as j}from"react/jsx-runtime";function C(e){return j("div",{role:"status",className:"flex flex-col items-center justify-center gap-2 px-4 py-12 text-center text-muted-foreground",children:[j("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:"h-8 w-8","aria-hidden":"true",children:[L("circle",{cx:"11",cy:"11",r:"7"}),L("path",{d:"m21 21-4.3-4.3"})]}),L("p",{className:"text-sm font-medium text-foreground",children:"No results"}),L("p",{className:"text-xs text-muted-foreground",children:"Try adjusting your filters or search terms."})]})}import{jsx as ae}from"react/jsx-runtime";function I({children:e}){return ae("div",{className:"flex flex-col gap-3",children:e})}import{jsx as x,jsxs as ne}from"react/jsx-runtime";function D(e){return x("div",{className:"flex flex-col gap-3 p-3",role:"status","aria-busy":"true","aria-label":"Loading results",children:Array.from({length:3}).map((i,t)=>ne("div",{className:"flex flex-col gap-2 motion-safe:animate-pulse",children:[x("div",{className:"aspect-video w-full rounded-md bg-muted"}),x("div",{className:"h-4 w-2/3 rounded-md bg-muted"}),x("div",{className:"h-3 w-1/3 rounded-md bg-muted"})]},t))})}import{jsx as le}from"react/jsx-runtime";function M({point:e}){let i=e.entity??{};return le("span",{className:"rounded-full border bg-background px-2 py-0.5 text-xs font-medium tabular-nums shadow-sm",children:i.price??""})}import{jsx as c,jsxs as k}from"react/jsx-runtime";function F({entity:e,onClose:i}){let t=e??{};return k("div",{className:"relative w-64 rounded-lg border bg-popover p-3 text-popover-foreground shadow-md",role:"group","aria-label":"Location details",children:[c("button",{type:"button",onClick:i,"aria-label":"Close",className:"absolute right-2 top-2 rounded-md p-1 text-muted-foreground motion-safe:transition-colors hover:bg-foreground/[0.06] hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",children:k("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round",className:"h-4 w-4","aria-hidden":"true",children:[c("path",{d:"M18 6 6 18"}),c("path",{d:"m6 6 12 12"})]})}),k("div",{className:"pr-6",children:[t.title&&c("div",{className:"font-medium",children:t.title}),t.subtitle&&c("div",{className:"text-sm text-muted-foreground",children:t.subtitle}),t.price!=null&&c("div",{className:"mt-1 font-semibold tabular-nums",children:t.price})]})]})}import{jsx as pe}from"react/jsx-runtime";function S({count:e,total:i}){let t=i!=null&&i!==e?`${e} of ${i} results`:`${e} results`;return pe("div",{className:"text-sm tabular-nums text-muted-foreground",children:t})}import{jsx as de}from"react/jsx-runtime";function T({value:e,onChange:i,placeholder:t}){return de("input",{type:"search",value:e,placeholder:t,onChange:r=>i(r.target.value),"aria-label":t??"Search",className:s("h-9 w-full rounded-md border bg-background px-3 text-sm text-foreground placeholder:text-muted-foreground","focus-visible:border-ring focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring")})}import{jsx as me}from"react/jsx-runtime";function R({children:e}){return me("aside",{className:"flex w-full flex-col gap-4 p-4 md:border-r md:border-border",children:e})}import{jsx as ue}from"react/jsx-runtime";function A({children:e}){return ue("div",{className:"flex items-center gap-2 border-b p-2",children:e})}var g={Card:w,Marker:M,Popup:F,Sidebar:R,FilterPanel:I,Search:T,Empty:C,Loading:D,ResultHeader:S,Toolbar:A};import{jsx as ce}from"react/jsx-runtime";function fe({children:e}){return ce(v,{...g,children:e})}import{useEffect as Le,useState as xe}from"react";import{useEffect as ge,useState as be}from"react";import{jsx as o,jsxs as b}from"react/jsx-runtime";var ve=o("p",{className:"px-4 text-center text-sm text-muted-foreground",children:"Map unavailable - provide a Google Maps API key"});function E({search:e,className:i,toolbarEnd:t,autoFetch:r=!0,mapCenter:l,mapZoom:a}){let p=Z(),{Search:u}=$(),[f,y]=be("list");ge(()=>{r!==!1&&p.applyFilters({})},[p,r]);let h=f==="map"?"hidden md:block":"block",P=f==="list"?"hidden md:block":"block";return b("div",{className:s("flex h-full min-h-0 w-full flex-col bg-background text-foreground",i),"data-slot":"listing-layout",children:[b("div",{className:"sticky top-0 z-10 flex flex-wrap items-end gap-3 border-b border-border bg-background p-3","data-slot":"listing-layout-filter-bar",children:[e&&o("div",{className:"w-full min-w-0 sm:w-auto sm:max-w-xs sm:flex-1",children:o(u,{value:e.value,onChange:e.onChange,placeholder:e.placeholder})}),o(G,{className:"flex flex-wrap items-end gap-3",groupClassName:"min-w-0"}),b("div",{className:"ml-auto flex items-center gap-3",children:[o(X,{}),t]})]}),o("div",{className:"flex items-center justify-center gap-1 border-b border-border bg-background p-2 md:hidden","data-slot":"listing-layout-mobile-toggle",children:o("div",{role:"group","aria-label":"View",className:"inline-flex rounded-md border border-border p-0.5",children:[{view:"list",label:"List"},{view:"map",label:"Map"}].map(({view:d,label:n})=>o("button",{type:"button","aria-pressed":f===d,onClick:()=>y(d),className:s("rounded-[5px] px-3 py-1 text-sm font-medium motion-safe:transition-colors",f===d?"bg-primary text-primary-foreground":"text-muted-foreground hover:bg-foreground/[0.06] hover:text-foreground"),children:n},d))})}),b("div",{className:"grid min-h-0 flex-1 md:grid-cols-[minmax(340px,42%)_1fr]","data-slot":"listing-layout-split",children:[b("div",{className:s("min-h-0 overflow-y-auto p-3",h),"data-slot":"listing-layout-list",children:[o(q,{className:"grid content-start gap-3 [grid-template-columns:repeat(auto-fill,minmax(200px,1fr))]"}),o("div",{className:"mt-4 flex justify-center",children:o(Q,{})})]}),o("div",{className:s("min-h-0 md:sticky md:top-0",P),"data-slot":"listing-layout-map",children:o(J,{center:l,zoom:a,fallback:ve})})]})]})}import{jsx as V}from"react/jsx-runtime";function ee(e){return"provider"in e}function ye(e){let i=e!=null&&!ee(e),t=i?e.apiKey:void 0,r=i?e.mapId:void 0,[l,a]=xe(()=>!e||ee(e)?{ready:!0,provider:e?.provider}:{ready:!1});return Le(()=>{if(!t)return;let p=!1;return import("../maps/google/index.js").then(({googleProvider:u})=>{p||a({ready:!0,provider:u({apiKey:t,mapId:r})})}),()=>{p=!0}},[t,r]),l}function he(e){let{datasets:i,filters:t,map:r,components:l,urlSync:a,initialFilters:p,config:u,className:f,search:y,autoFetch:h}=e,{ready:P,provider:d}=ye(r);if(!P)return null;let n=[];for(let ie of i)n.push(O(ie));t&&n.push(W(t)),d&&n.push(_(d)),a instanceof K&&n.push(z(a)),p&&n.push(B(p)),u&&n.push(H(u));let te=U(...n),re={...g,...l};return V(Y,{...te,children:V(v,{...re,children:V(E,{className:f,search:y,autoFetch:h,mapCenter:r?.center,mapZoom:r?.zoom})})})}export{w as DefaultCard,C as DefaultEmpty,I as DefaultFilterPanel,D as DefaultLoading,M as DefaultMarker,F as DefaultPopup,S as DefaultResultHeader,T as DefaultSearch,R as DefaultSidebar,A as DefaultToolbar,he as ListingApp,fe as ListingComponentsProviderWithDefaults,E as ListingLayout,s as cn,g as shadcnDefaultComponents};
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});"use client";
2
+ var _chunkN3OZ2HK2cjs = require('../chunk-N3OZ2HK2.cjs');var _chunk5O36WI7Hcjs = require('../chunk-5O36WI7H.cjs');var _jsxruntime = require('react/jsx-runtime');function L({children:o}){return _jsxruntime.jsx.call(void 0, _chunk5O36WI7Hcjs.p,{..._chunkN3OZ2HK2cjs.l,children:o})}exports.BottomNav = _chunkN3OZ2HK2cjs.m; exports.BottomSheet = _chunkN3OZ2HK2cjs.n; exports.ListingApp = _chunkN3OZ2HK2cjs.p; exports.StyledCard = _chunkN3OZ2HK2cjs.b; exports.StyledComponentsProviderWithDefaults = L; exports.StyledEmpty = _chunkN3OZ2HK2cjs.c; exports.StyledFilterPanel = _chunkN3OZ2HK2cjs.d; exports.StyledListingLayout = _chunkN3OZ2HK2cjs.o; exports.StyledLoading = _chunkN3OZ2HK2cjs.e; exports.StyledMarker = _chunkN3OZ2HK2cjs.f; exports.StyledPopup = _chunkN3OZ2HK2cjs.g; exports.StyledResultHeader = _chunkN3OZ2HK2cjs.h; exports.StyledSearch = _chunkN3OZ2HK2cjs.i; exports.StyledSidebar = _chunkN3OZ2HK2cjs.j; exports.StyledToolbar = _chunkN3OZ2HK2cjs.k; exports.styledDefaultComponents = _chunkN3OZ2HK2cjs.l;