@usereactify/search 5.59.0-beta.1 → 5.59.0-beta.2

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 (36) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/package.json +1 -1
  3. package/dist/src/components/ReactifySearchProvider/ReactifySearchProvider.d.ts +14 -3
  4. package/dist/src/components/ReactifySearchProvider/ReactifySearchProvider.js +5 -6
  5. package/dist/src/components/ReactifySearchProvider/ReactifySearchProvider.js.map +1 -1
  6. package/dist/src/components/Sensor/SensorCollection.js +2 -1
  7. package/dist/src/components/Sensor/SensorCollection.js.map +1 -1
  8. package/dist/src/components/Sensor/SensorCuratedPageCollection.d.ts +1 -0
  9. package/dist/src/components/Sensor/SensorCuratedPageCollection.js +22 -0
  10. package/dist/src/components/Sensor/SensorCuratedPageCollection.js.map +1 -0
  11. package/dist/src/components/Sensor/SensorCuratedPageSearch.d.ts +1 -0
  12. package/dist/src/components/Sensor/SensorCuratedPageSearch.js +21 -0
  13. package/dist/src/components/Sensor/SensorCuratedPageSearch.js.map +1 -0
  14. package/dist/src/components/Sensor/Sensors.js +18 -0
  15. package/dist/src/components/Sensor/Sensors.js.map +1 -1
  16. package/dist/src/components/Sensor/index.d.ts +4 -1
  17. package/dist/src/components/Sensor/index.js +5 -1
  18. package/dist/src/components/Sensor/index.js.map +1 -1
  19. package/dist/src/hooks/useReactifySearchContext.d.ts +17 -1
  20. package/dist/src/hooks/useReactifySearchContext.js +30 -4
  21. package/dist/src/hooks/useReactifySearchContext.js.map +1 -1
  22. package/dist/src/types/config.d.ts +7 -5
  23. package/dist/src/types/config.js.map +1 -1
  24. package/dist/src/types/firestore.d.ts +84 -392
  25. package/dist/src/types/firestore.js +53 -84
  26. package/dist/src/types/firestore.js.map +1 -1
  27. package/dist/src/utility/liquid.d.ts +8 -1
  28. package/dist/src/utility/liquid.js +32 -11
  29. package/dist/src/utility/liquid.js.map +1 -1
  30. package/dist/src/utility/props.d.ts +206 -7
  31. package/dist/src/utility/props.js +74 -67
  32. package/dist/src/utility/props.js.map +1 -1
  33. package/dist/src/utility/queries.d.ts +391 -0
  34. package/dist/src/utility/queries.js +225 -0
  35. package/dist/src/utility/queries.js.map +1 -0
  36. package/package.json +1 -1
@@ -37,9 +37,9 @@ export declare const getPropsFilterGroup: (options: GeneratePropsFilterGroupOpti
37
37
  source: typeof ReactiveList;
38
38
  onData: ResultsDataListener | undefined;
39
39
  } | {
40
+ source: import("react").ComponentClass<import("@usereactify/search-internals/lib/components/basic/ReactiveComponent").ReactiveComponentProps, any>;
40
41
  componentId: string;
41
42
  customQuery: () => unknown;
42
- source: import("react").ComponentClass<import("@usereactify/search-internals/lib/components/basic/ReactiveComponent").ReactiveComponentProps, any>;
43
43
  } | {
44
44
  URLParams: boolean;
45
45
  componentId: string;
@@ -189,16 +189,17 @@ export declare const getPropsFilterGroupOption: (options: GeneratePropsFilterGro
189
189
  };
190
190
  };
191
191
  export declare const getPropsSensors: (options: GeneratePropsSensorOptions) => ({
192
+ source: import("react").ComponentClass<import("@usereactify/search-internals/lib/components/basic/ReactiveComponent").ReactiveComponentProps, any>;
192
193
  componentId: string;
193
194
  customQuery: () => unknown;
194
- source: import("react").ComponentClass<import("@usereactify/search-internals/lib/components/basic/ReactiveComponent").ReactiveComponentProps, any>;
195
195
  } | null)[];
196
196
  export declare const getPropsSensorCustom: (options: GeneratePropsSensorOptions) => {
197
+ source: import("react").ComponentClass<import("@usereactify/search-internals/lib/components/basic/ReactiveComponent").ReactiveComponentProps, any>;
197
198
  componentId: string;
198
199
  customQuery: () => unknown;
199
- source: import("react").ComponentClass<import("@usereactify/search-internals/lib/components/basic/ReactiveComponent").ReactiveComponentProps, any>;
200
200
  }[];
201
201
  export declare const getPropsSensorCollection: (options: GeneratePropsSensorOptions) => {
202
+ source: import("react").ComponentClass<import("@usereactify/search-internals/lib/components/basic/ReactiveComponent").ReactiveComponentProps, any>;
202
203
  componentId: string;
203
204
  customQuery: () => {
204
205
  query: {
@@ -227,9 +228,208 @@ export declare const getPropsSensorCollection: (options: GeneratePropsSensorOpti
227
228
  };
228
229
  };
229
230
  } | null;
231
+ } | null;
232
+ export declare const getPropsSensorCuratedPageCollection: ({ provider, config, }: GeneratePropsSensorOptions) => {
233
+ source: import("react").ComponentClass<import("@usereactify/search-internals/lib/components/basic/ReactiveComponent").ReactiveComponentProps, any>;
234
+ componentId: string;
235
+ customQuery: () => {
236
+ query: {
237
+ function_score: {
238
+ query: {
239
+ bool: {
240
+ must: Record<string, any>[];
241
+ };
242
+ };
243
+ functions: ({
244
+ filter: {
245
+ wildcard: {
246
+ [x: string]: string;
247
+ };
248
+ bool?: undefined;
249
+ term?: undefined;
250
+ range?: undefined;
251
+ };
252
+ weight: number;
253
+ } | {
254
+ filter: {
255
+ bool: {
256
+ must_not: {
257
+ wildcard: {
258
+ [x: string]: string;
259
+ };
260
+ };
261
+ };
262
+ wildcard?: undefined;
263
+ term?: undefined;
264
+ range?: undefined;
265
+ };
266
+ weight: number;
267
+ } | {
268
+ filter: {
269
+ term: {
270
+ [x: string]: string;
271
+ };
272
+ wildcard?: undefined;
273
+ bool?: undefined;
274
+ range?: undefined;
275
+ };
276
+ weight: number;
277
+ } | {
278
+ filter: {
279
+ range: {
280
+ [x: string]: {
281
+ gt: number;
282
+ };
283
+ };
284
+ wildcard?: undefined;
285
+ bool?: undefined;
286
+ term?: undefined;
287
+ };
288
+ weight: number;
289
+ } | {
290
+ filter: {
291
+ range: {
292
+ [x: string]: {
293
+ lt: number;
294
+ };
295
+ };
296
+ wildcard?: undefined;
297
+ bool?: undefined;
298
+ term?: undefined;
299
+ };
300
+ weight: number;
301
+ })[];
302
+ score_mode: string;
303
+ boost_mode: string;
304
+ };
305
+ };
306
+ };
307
+ } | null;
308
+ export declare const getPropsSensorCuratedPageSearch: ({ provider, config, }: GeneratePropsSensorOptions) => {
230
309
  source: import("react").ComponentClass<import("@usereactify/search-internals/lib/components/basic/ReactiveComponent").ReactiveComponentProps, any>;
310
+ componentId: string;
311
+ customQuery: () => {
312
+ query: {
313
+ function_score: {
314
+ query: {
315
+ bool: {
316
+ should: {
317
+ match: {
318
+ [x: string]: {
319
+ query: string;
320
+ fuzziness: number;
321
+ analyzer: string;
322
+ };
323
+ };
324
+ }[];
325
+ terms?: {
326
+ markets: string[];
327
+ } | undefined;
328
+ };
329
+ };
330
+ functions: ({
331
+ filter: {
332
+ wildcard: {
333
+ [x: string]: string;
334
+ };
335
+ bool?: undefined;
336
+ term?: undefined;
337
+ range?: undefined;
338
+ };
339
+ weight: number;
340
+ } | {
341
+ filter: {
342
+ bool: {
343
+ must_not: {
344
+ wildcard: {
345
+ [x: string]: string;
346
+ };
347
+ };
348
+ };
349
+ wildcard?: undefined;
350
+ term?: undefined;
351
+ range?: undefined;
352
+ };
353
+ weight: number;
354
+ } | {
355
+ filter: {
356
+ term: {
357
+ [x: string]: string;
358
+ };
359
+ wildcard?: undefined;
360
+ bool?: undefined;
361
+ range?: undefined;
362
+ };
363
+ weight: number;
364
+ } | {
365
+ filter: {
366
+ range: {
367
+ [x: string]: {
368
+ gt: number;
369
+ };
370
+ };
371
+ wildcard?: undefined;
372
+ bool?: undefined;
373
+ term?: undefined;
374
+ };
375
+ weight: number;
376
+ } | {
377
+ filter: {
378
+ range: {
379
+ [x: string]: {
380
+ lt: number;
381
+ };
382
+ };
383
+ wildcard?: undefined;
384
+ bool?: undefined;
385
+ term?: undefined;
386
+ };
387
+ weight: number;
388
+ } | {
389
+ filter: {
390
+ match: {
391
+ [x: string]: {
392
+ query: string;
393
+ fuzziness: number;
394
+ analyzer: string;
395
+ };
396
+ };
397
+ bool?: undefined;
398
+ };
399
+ weight: number;
400
+ } | {
401
+ filter: {
402
+ bool: {
403
+ must_not: {
404
+ match: {
405
+ [x: string]: {
406
+ query: string;
407
+ fuzziness: number;
408
+ analyzer: string;
409
+ };
410
+ };
411
+ };
412
+ should: {
413
+ match: {
414
+ [x: string]: {
415
+ query: string;
416
+ fuzziness: number;
417
+ };
418
+ };
419
+ };
420
+ };
421
+ match?: undefined;
422
+ };
423
+ weight: number;
424
+ })[];
425
+ score_mode: string;
426
+ boost_mode: string;
427
+ };
428
+ };
429
+ } | null;
231
430
  } | null;
232
431
  export declare const getPropsSensorPublished: (options: GeneratePropsSensorOptions) => {
432
+ source: import("react").ComponentClass<import("@usereactify/search-internals/lib/components/basic/ReactiveComponent").ReactiveComponentProps, any>;
233
433
  componentId: string;
234
434
  customQuery: () => {
235
435
  query: {
@@ -256,9 +456,9 @@ export declare const getPropsSensorPublished: (options: GeneratePropsSensorOptio
256
456
  bool?: undefined;
257
457
  };
258
458
  };
259
- source: import("react").ComponentClass<import("@usereactify/search-internals/lib/components/basic/ReactiveComponent").ReactiveComponentProps, any>;
260
459
  };
261
460
  export declare const getPropsSensorInventoryAvailable: (options: GeneratePropsSensorOptions) => {
461
+ source: import("react").ComponentClass<import("@usereactify/search-internals/lib/components/basic/ReactiveComponent").ReactiveComponentProps, any>;
262
462
  componentId: string;
263
463
  customQuery: () => {
264
464
  query: {
@@ -297,18 +497,17 @@ export declare const getPropsSensorInventoryAvailable: (options: GeneratePropsSe
297
497
  };
298
498
  };
299
499
  };
300
- source: import("react").ComponentClass<import("@usereactify/search-internals/lib/components/basic/ReactiveComponent").ReactiveComponentProps, any>;
301
500
  } | null;
302
501
  export declare const getPropsSensorSort: (options: GeneratePropsSensorOptions & {
303
502
  searchTerm?: string;
304
503
  sortOption?: string;
305
504
  }) => {
505
+ source: import("react").ComponentClass<import("@usereactify/search-internals/lib/components/basic/ReactiveComponent").ReactiveComponentProps, any>;
306
506
  componentId: string;
307
507
  customQuery: () => {
308
508
  sort: any[];
309
509
  query: Record<string, any> | undefined;
310
510
  };
311
- source: import("react").ComponentClass<import("@usereactify/search-internals/lib/components/basic/ReactiveComponent").ReactiveComponentProps, any>;
312
511
  };
313
512
  export declare const getPropsBase: (options: GeneratePropsBase) => {
314
513
  app: string;
@@ -321,7 +520,7 @@ export declare const getPropsBase: (options: GeneratePropsBase) => {
321
520
  transformResponse: (response: any) => Promise<any>;
322
521
  headers: {
323
522
  "x-reactify-shop": string;
324
- "x-reactify-mode": "search" | "collection" | "instant-search";
523
+ "x-reactify-mode": "search" | "collection" | "instant-search" | "curated-page";
325
524
  "x-reactify-client-id": string | undefined;
326
525
  "x-reactify-client-version": string;
327
526
  };
@@ -12,7 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.getPropsFilterSlider = exports.getPropsFilterRange = exports.getPropsFilterList = exports.getPropsShared = exports.getPropsReact = exports.getPropsResults = exports.getPropsBase = exports.getPropsSensorSort = exports.getPropsSensorInventoryAvailable = exports.getPropsSensorPublished = exports.getPropsSensorCollection = exports.getPropsSensorCustom = exports.getPropsSensors = exports.getPropsFilterGroupOption = exports.getPropsFilterGroup = void 0;
15
+ exports.getPropsFilterSlider = exports.getPropsFilterRange = exports.getPropsFilterList = exports.getPropsShared = exports.getPropsReact = exports.getPropsResults = exports.getPropsBase = exports.getPropsSensorSort = exports.getPropsSensorInventoryAvailable = exports.getPropsSensorPublished = exports.getPropsSensorCuratedPageSearch = exports.getPropsSensorCuratedPageCollection = exports.getPropsSensorCollection = exports.getPropsSensorCustom = exports.getPropsSensors = exports.getPropsFilterGroupOption = exports.getPropsFilterGroup = void 0;
16
16
  const search_internals_1 = require("@usereactify/search-internals");
17
17
  const components_1 = require("../components");
18
18
  const curation_1 = require("./curation");
@@ -20,6 +20,7 @@ const sortOption_1 = require("./sortOption");
20
20
  const filters_1 = require("./filters");
21
21
  const hooks_1 = require("../hooks");
22
22
  const package_json_1 = __importDefault(require("../../package.json"));
23
+ const queries_1 = require("./queries");
23
24
  const getPropsFilterGroup = (options) => {
24
25
  var _a, _b;
25
26
  return [
@@ -66,23 +67,24 @@ const getPropsSensorCustom = (options) => {
66
67
  ? options.config.sensors.collection
67
68
  : options.config.sensors.search;
68
69
  return sensors.map((sensor, index) => ({
70
+ source: search_internals_1.ReactiveComponent,
69
71
  componentId: `SensorCustom_${index}`,
70
72
  customQuery: () => sensor,
71
- source: search_internals_1.ReactiveComponent,
72
73
  }));
73
74
  };
74
75
  exports.getPropsSensorCustom = getPropsSensorCustom;
75
76
  const getPropsSensorCollection = (options) => {
76
- if (options.provider.mode !== "collection") {
77
+ if (options.provider.mode !== "collection")
77
78
  return null;
78
- }
79
79
  return {
80
+ source: search_internals_1.ReactiveComponent,
80
81
  componentId: "SensorCollection",
81
82
  customQuery: () => {
82
- if (options.provider.mode !== "collection") {
83
+ if (options.provider.mode !== "collection")
83
84
  return null;
84
- }
85
85
  const conditions = [];
86
+ const handle = options.provider.collectionHandle;
87
+ const market = options.provider.market;
86
88
  if (options.provider.market) {
87
89
  conditions.push({
88
90
  nested: {
@@ -93,11 +95,7 @@ const getPropsSensorCollection = (options) => {
93
95
  {
94
96
  nested: {
95
97
  path: "collections",
96
- query: {
97
- term: {
98
- "collections.handle.keyword": options.provider.collectionHandle,
99
- },
100
- },
98
+ query: { term: { "collections.handle.keyword": handle } },
101
99
  },
102
100
  },
103
101
  {
@@ -105,7 +103,7 @@ const getPropsSensorCollection = (options) => {
105
103
  path: "curations",
106
104
  query: {
107
105
  term: {
108
- "curations.collectionHandle.keyword": options.provider.collectionHandle,
106
+ "curations.collectionHandle.keyword": handle,
109
107
  },
110
108
  },
111
109
  },
@@ -115,11 +113,7 @@ const getPropsSensorCollection = (options) => {
115
113
  {
116
114
  nested: {
117
115
  path: "curations",
118
- query: {
119
- term: {
120
- "curations.markets.keyword": options.provider.market,
121
- },
122
- },
116
+ query: { term: { "curations.markets.keyword": market } },
123
117
  },
124
118
  },
125
119
  ],
@@ -135,20 +129,14 @@ const getPropsSensorCollection = (options) => {
135
129
  {
136
130
  nested: {
137
131
  path: "collections",
138
- query: {
139
- term: {
140
- "collections.handle.keyword": options.provider.collectionHandle,
141
- },
142
- },
132
+ query: { term: { "collections.handle.keyword": handle } },
143
133
  },
144
134
  },
145
135
  {
146
136
  nested: {
147
137
  path: "curations",
148
138
  query: {
149
- term: {
150
- "curations.collectionHandle.keyword": options.provider.collectionHandle,
151
- },
139
+ term: { "curations.collectionHandle.keyword": handle },
152
140
  },
153
141
  },
154
142
  },
@@ -157,12 +145,61 @@ const getPropsSensorCollection = (options) => {
157
145
  },
158
146
  };
159
147
  },
160
- source: search_internals_1.ReactiveComponent,
161
148
  };
162
149
  };
163
150
  exports.getPropsSensorCollection = getPropsSensorCollection;
151
+ const getPropsSensorCuratedPageCollection = ({ provider, config, }) => {
152
+ if (provider.mode !== "curated-page")
153
+ return null;
154
+ if (provider.variation !== "collection")
155
+ return null;
156
+ const handle = provider.handle;
157
+ return {
158
+ source: search_internals_1.ReactiveComponent,
159
+ componentId: "SensorCuratedPageCollection",
160
+ customQuery: () => {
161
+ var _a;
162
+ const curation = config.curations.find((curation) => curation.collectionHandle === handle);
163
+ const function_score = (0, queries_1.generateCollectionFunctionScore)({
164
+ collectionHandle: handle,
165
+ boostingRules: (_a = curation === null || curation === void 0 ? void 0 : curation.boostings) !== null && _a !== void 0 ? _a : [],
166
+ markets: (curation === null || curation === void 0 ? void 0 : curation.markets) || [],
167
+ market: provider.market,
168
+ });
169
+ return { query: { function_score } };
170
+ },
171
+ };
172
+ };
173
+ exports.getPropsSensorCuratedPageCollection = getPropsSensorCuratedPageCollection;
174
+ const getPropsSensorCuratedPageSearch = ({ provider, config, }) => {
175
+ if (provider.mode !== "curated-page")
176
+ return null;
177
+ if (provider.variation !== "search")
178
+ return null;
179
+ const searchTerm = provider.searchTerm;
180
+ return {
181
+ source: search_internals_1.ReactiveComponent,
182
+ componentId: "SensorCuratedPageSearch",
183
+ customQuery: () => {
184
+ var _a;
185
+ const curation = config.curations.find((curation) => curation.searchTerm === searchTerm);
186
+ if (!curation)
187
+ return null;
188
+ const function_score = (0, queries_1.generateSearchFunctionScore)({
189
+ searchTerm: searchTerm,
190
+ searchableFields: config.searchableFields,
191
+ boostingRules: (_a = curation.boostings) !== null && _a !== void 0 ? _a : [],
192
+ markets: curation.markets,
193
+ market: provider.market,
194
+ });
195
+ return { query: { function_score } };
196
+ },
197
+ };
198
+ };
199
+ exports.getPropsSensorCuratedPageSearch = getPropsSensorCuratedPageSearch;
164
200
  const getPropsSensorPublished = (options) => {
165
201
  return {
202
+ source: search_internals_1.ReactiveComponent,
166
203
  componentId: "SensorPublished",
167
204
  customQuery: () => {
168
205
  if (options.provider.market) {
@@ -170,30 +207,17 @@ const getPropsSensorPublished = (options) => {
170
207
  query: {
171
208
  bool: {
172
209
  must: [
173
- {
174
- match: {
175
- markets: options.provider.market,
176
- },
177
- },
178
- {
179
- match: {
180
- published: true,
181
- },
182
- },
210
+ { match: { markets: options.provider.market } },
211
+ { match: { published: true } },
183
212
  ],
184
213
  },
185
214
  },
186
215
  };
187
216
  }
188
217
  return {
189
- query: {
190
- match: {
191
- published: true,
192
- },
193
- },
218
+ query: { match: { published: true } },
194
219
  };
195
220
  },
196
- source: search_internals_1.ReactiveComponent,
197
221
  };
198
222
  };
199
223
  exports.getPropsSensorPublished = getPropsSensorPublished;
@@ -203,6 +227,7 @@ const getPropsSensorInventoryAvailable = (options) => {
203
227
  return null;
204
228
  }
205
229
  return {
230
+ source: search_internals_1.ReactiveComponent,
206
231
  componentId: "SensorInventoryAvailable",
207
232
  customQuery: () => ({
208
233
  query: {
@@ -249,7 +274,6 @@ const getPropsSensorInventoryAvailable = (options) => {
249
274
  },
250
275
  },
251
276
  }),
252
- source: search_internals_1.ReactiveComponent,
253
277
  };
254
278
  };
255
279
  exports.getPropsSensorInventoryAvailable = getPropsSensorInventoryAvailable;
@@ -268,12 +292,12 @@ const getPropsSensorSort = (options) => {
268
292
  curation: curation,
269
293
  });
270
294
  return {
295
+ source: search_internals_1.ReactiveComponent,
271
296
  componentId: "SensorSort",
272
297
  customQuery: () => ({
273
298
  sort,
274
299
  query,
275
300
  }),
276
- source: search_internals_1.ReactiveComponent,
277
301
  };
278
302
  };
279
303
  exports.getPropsSensorSort = getPropsSensorSort;
@@ -482,15 +506,13 @@ const getPropsShared = (options, filterGroupOption) => {
482
506
  return search_internals_1.ReactiveComponent;
483
507
  }
484
508
  if (filterGroupOption.displayType === "single") {
485
- if (filterGroupOption.displayView === "range") {
509
+ if (filterGroupOption.displayView === "range")
486
510
  return search_internals_1.SingleRange;
487
- }
488
511
  return search_internals_1.SingleList;
489
512
  }
490
513
  if (filterGroupOption.displayType === "multi") {
491
- if (filterGroupOption.displayView === "range") {
514
+ if (filterGroupOption.displayView === "range")
492
515
  return search_internals_1.MultiRange;
493
- }
494
516
  return search_internals_1.MultiList;
495
517
  }
496
518
  return;
@@ -551,16 +573,8 @@ const getPropsFilterSlider = (filterGroupOption, query, value) => {
551
573
  const filterValue = value !== null && value !== void 0 ? value : JSON.parse((_a = new URLSearchParams(typeof window === "undefined" ? query : window.location.search).get(filterGroupOption.handle)) !== null && _a !== void 0 ? _a : "[0,0]");
552
574
  const defaultQuery = {
553
575
  aggs: {
554
- min: {
555
- min: {
556
- field: filterGroupOption.field,
557
- },
558
- },
559
- max: {
560
- max: {
561
- field: filterGroupOption.field,
562
- },
563
- },
576
+ min: { min: { field: filterGroupOption.field } },
577
+ max: { max: { field: filterGroupOption.field } },
564
578
  },
565
579
  };
566
580
  const customQuery = (() => {
@@ -574,11 +588,7 @@ const getPropsFilterSlider = (filterGroupOption, query, value) => {
574
588
  {
575
589
  bool: {
576
590
  must: [
577
- {
578
- match: {
579
- published: true,
580
- },
581
- },
591
+ { match: { published: true } },
582
592
  {
583
593
  range: {
584
594
  [filterGroupOption.field]: {
@@ -596,10 +606,7 @@ const getPropsFilterSlider = (filterGroupOption, query, value) => {
596
606
  },
597
607
  };
598
608
  })();
599
- return {
600
- defaultQuery,
601
- customQuery,
602
- };
609
+ return { defaultQuery, customQuery };
603
610
  };
604
611
  exports.getPropsFilterSlider = getPropsFilterSlider;
605
612
  //# sourceMappingURL=props.js.map