@mapvx/website-component 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -274,9 +274,10 @@ The web component accepts the following input properties to customize its behavi
274
274
 
275
275
  The web component emits custom events that you can listen to for user interactions:
276
276
 
277
- | Event Name | Type | Description |
278
- | -------------- | -------- | --------------------------------------------------------------- |
279
- | `cardSelected` | `string` | Emitted when a location card is selected. Contains the card ID. |
277
+ | Event Name | Type | Description |
278
+ | -------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------ |
279
+ | `cardSelected` | `string` | ⚠️ **Deprecated**: Use `userAction` with type `show-place` instead. Emitted when a location card is selected. Contains the card ID. |
280
+ | `userAction` | `UserAction` | Emitted when a user performs an action (filter selection, search, place navigation, etc.). Contains action type and associated data. |
280
281
 
281
282
  ### Output Usage Examples
282
283
 
@@ -284,30 +285,30 @@ The web component emits custom events that you can listen to for user interactio
284
285
 
285
286
  ```javascript
286
287
  // Wait for the web component to be registered
287
- function setupCardSelectedListener() {
288
+ function setupUserActionListener() {
288
289
  const element = document.querySelector('mapvx-website')
289
290
  if (element) {
290
- element.addEventListener('cardSelected', (event) => {
291
- if (event instanceof CustomEvent) {
292
- const cardId = event.detail
293
- console.log('Card selected:', cardId)
294
- // Handle card selection
291
+ element.addEventListener('userAction', (event) => {
292
+ if (event instanceof CustomEvent && event.detail.type === 'show-place') {
293
+ const placeId = event.detail.data.placeId
294
+ console.log('Place shown:', placeId)
295
+ // Handle place display
295
296
  }
296
297
  })
297
298
  } else {
298
299
  // Retry if element is not yet available
299
- setTimeout(setupCardSelectedListener, 100)
300
+ setTimeout(setupUserActionListener, 100)
300
301
  }
301
302
  }
302
303
 
303
304
  // Check if web component is already registered
304
305
  if (customElements.get('mapvx-website')) {
305
- setupCardSelectedListener()
306
+ setupUserActionListener()
306
307
  } else {
307
308
  // Wait for registration
308
309
  const checkInterval = setInterval(() => {
309
310
  if (customElements.get('mapvx-website')) {
310
- setupCardSelectedListener()
311
+ setupUserActionListener()
311
312
  clearInterval(checkInterval)
312
313
  }
313
314
  }, 100)
@@ -316,7 +317,7 @@ if (customElements.get('mapvx-website')) {
316
317
 
317
318
  #### Update Browser URL with `history.pushState`
318
319
 
319
- You can also react to the `cardSelected` event to change the browser URL without a full page reload, which is especially useful in SSR apps looking to keep client-side navigation in sync with the selected place. Add this script to your HTML page after the web component:s
320
+ You can react to user actions to change the browser URL without a full page reload, which is especially useful in SSR apps looking to keep client-side navigation in sync with the selected place.
320
321
 
321
322
  ```html
322
323
  <script>
@@ -328,19 +329,52 @@ You can also react to the `cardSelected` event to change the browser URL without
328
329
  return
329
330
  }
330
331
 
331
- const handleCardSelected = (event) => {
332
+ const handleUserAction = (event) => {
332
333
  if (event instanceof CustomEvent) {
333
- const cardId = event.detail
334
- // Update URL using history.pushState
335
- history.pushState(
336
- { page: 'profile', id: cardId },
337
- '',
338
- `${location.pathname}?tenant=${cardId}`,
339
- )
334
+ const action = event.detail
335
+ switch (action.type) {
336
+ case 'return-to-home':
337
+ case 'select-filter': {
338
+ const { filter } = action.data
339
+ history.pushState(
340
+ { page: 'home', filter },
341
+ '',
342
+ `${location.pathname}?tab=${encodeURIComponent(filter)}`,
343
+ )
344
+ break
345
+ }
346
+ case 'show-place': {
347
+ const { placeId } = action.data
348
+ history.pushState(
349
+ { page: 'profile', id: placeId },
350
+ '',
351
+ `${location.pathname}?tenant=${placeId}`,
352
+ )
353
+ break
354
+ }
355
+ case 'search': {
356
+ const { searchTerm } = action.data
357
+ history.pushState(
358
+ { page: 'search', term: searchTerm },
359
+ '',
360
+ `${location.pathname}?search=${encodeURIComponent(searchTerm)}`,
361
+ )
362
+ break
363
+ }
364
+ case 'select-destination': {
365
+ const { destinationId } = action.data
366
+ history.pushState(
367
+ { page: 'route', id: destinationId },
368
+ '',
369
+ `${location.pathname}?destination=${destinationId}`,
370
+ )
371
+ break
372
+ }
373
+ }
340
374
  }
341
375
  }
342
376
 
343
- element.addEventListener('cardSelected', handleCardSelected)
377
+ element.addEventListener('userAction', handleUserAction)
344
378
  }
345
379
 
346
380
  // Check if web component is already registered
@@ -370,18 +404,214 @@ function App() {
370
404
  const element = webComponentRef.current
371
405
  if (!element) return
372
406
 
373
- const handleCardSelected = (event) => {
407
+ const handleUserAction = (event) => {
408
+ if (event instanceof CustomEvent && event.detail.type === 'show-place') {
409
+ const placeId = event.detail.data.placeId
410
+ console.log('Place shown:', placeId)
411
+ // Handle place display
412
+ }
413
+ }
414
+
415
+ element.addEventListener('userAction', handleUserAction)
416
+
417
+ return () => {
418
+ element.removeEventListener('userAction', handleUserAction)
419
+ }
420
+ }, [])
421
+
422
+ return <mapvx-website ref={webComponentRef} api-key="your-api-key-here" />
423
+ }
424
+ ```
425
+
426
+ #### Vue
427
+
428
+ ```vue
429
+ <template>
430
+ <mapvx-website ref="webComponent" api-key="your-api-key-here" />
431
+ </template>
432
+
433
+ <script setup>
434
+ import { ref, onMounted, onUnmounted } from 'vue'
435
+
436
+ const webComponent = ref(null)
437
+
438
+ const handleUserAction = (event) => {
439
+ if (event instanceof CustomEvent && event.detail.type === 'show-place') {
440
+ const placeId = event.detail.data.placeId
441
+ console.log('Place shown:', placeId)
442
+ // Handle place display
443
+ }
444
+ }
445
+
446
+ onMounted(() => {
447
+ if (webComponent.value) {
448
+ webComponent.value.addEventListener('userAction', handleUserAction)
449
+ }
450
+ })
451
+
452
+ onUnmounted(() => {
453
+ if (webComponent.value) {
454
+ webComponent.value.removeEventListener('userAction', handleUserAction)
455
+ }
456
+ })
457
+ </script>
458
+ ```
459
+
460
+ #### Angular
461
+
462
+ ```typescript
463
+ import { Component, ElementRef, OnDestroy, ViewChild, AfterViewInit } from '@angular/core'
464
+
465
+ @Component({
466
+ selector: 'app-mapvx',
467
+ template: ` <mapvx-website #webComponent [attr.api-key]="apiKey" /> `,
468
+ })
469
+ export class MapvxComponent implements AfterViewInit, OnDestroy {
470
+ @ViewChild('webComponent', { static: false }) webComponentRef!: ElementRef<HTMLElement>
471
+
472
+ apiKey = 'your-api-key-here'
473
+ private userActionListener?: (event: Event) => void
474
+
475
+ ngAfterViewInit() {
476
+ this.setupUserActionListener()
477
+ }
478
+
479
+ private setupUserActionListener() {
480
+ const element = this.webComponentRef?.nativeElement
481
+ if (!element) {
482
+ // Retry if element is not yet available
483
+ setTimeout(() => this.setupUserActionListener(), 100)
484
+ return
485
+ }
486
+
487
+ this.userActionListener = (event: Event) => {
374
488
  if (event instanceof CustomEvent) {
375
- const cardId = event.detail
376
- console.log('Card selected:', cardId)
377
- // Handle card selection
489
+ const action = event.detail as { type: string; data: any }
490
+ if (action.type === 'show-place') {
491
+ const placeId = action.data.placeId
492
+ console.log('Place shown:', placeId)
493
+ // Handle place display
494
+ }
378
495
  }
379
496
  }
380
497
 
381
- element.addEventListener('cardSelected', handleCardSelected)
498
+ element.addEventListener('userAction', this.userActionListener)
499
+ }
500
+
501
+ ngOnDestroy() {
502
+ const element = this.webComponentRef?.nativeElement
503
+ if (element && this.userActionListener) {
504
+ element.removeEventListener('userAction', this.userActionListener)
505
+ }
506
+ }
507
+ }
508
+ ```
509
+
510
+ ### User Action Event
511
+
512
+ The `userAction` event provides detailed information about user interactions within the component. The event detail contains an object with `type` and `data` properties.
513
+
514
+ #### UserAction Types
515
+
516
+ | Type | Description | Data Structure |
517
+ | -------------------- | ------------------------------------------ | --------------------------- |
518
+ | `select-filter` | Emitted when a filter is selected | `{ filter: string }` |
519
+ | `show-place` | Emitted when a place is displayed | `{ placeId: string }` |
520
+ | `select-destination` | Emitted when a destination is selected | `{ destinationId: string }` |
521
+ | `search` | Emitted when a search is performed | `{ searchTerm: string }` |
522
+ | `return-to-home` | Emitted when user returns to the home view | `{ filter: string }` |
523
+
524
+ #### UserAction Usage Examples
525
+
526
+ #### Vanilla JavaScript
527
+
528
+ ```javascript
529
+ // Wait for the web component to be registered
530
+ function setupUserActionListener() {
531
+ const element = document.querySelector('mapvx-website')
532
+ if (element) {
533
+ element.addEventListener('userAction', (event) => {
534
+ if (event instanceof CustomEvent) {
535
+ const action = event.detail
536
+ console.log('User action:', action.type, action.data)
537
+
538
+ // Handle different action types
539
+ switch (action.type) {
540
+ case 'select-filter':
541
+ console.log('Filter selected:', action.data.filter)
542
+ break
543
+ case 'show-place':
544
+ console.log('Place shown:', action.data.placeId)
545
+ break
546
+ case 'select-destination':
547
+ console.log('Destination selected:', action.data.destinationId)
548
+ break
549
+ case 'search':
550
+ console.log('Search performed:', action.data.searchTerm)
551
+ break
552
+ case 'return-to-home':
553
+ console.log('Returned to home with filter:', action.data.filter)
554
+ break
555
+ }
556
+ }
557
+ })
558
+ } else {
559
+ // Retry if element is not yet available
560
+ setTimeout(setupUserActionListener, 100)
561
+ }
562
+ }
563
+
564
+ // Check if web component is already registered
565
+ if (customElements.get('mapvx-website')) {
566
+ setupUserActionListener()
567
+ } else {
568
+ // Wait for registration
569
+ const checkInterval = setInterval(() => {
570
+ if (customElements.get('mapvx-website')) {
571
+ setupUserActionListener()
572
+ clearInterval(checkInterval)
573
+ }
574
+ }, 100)
575
+ }
576
+ ```
577
+
578
+ #### React
579
+
580
+ ```jsx
581
+ import { useEffect, useRef } from 'react'
582
+
583
+ function App() {
584
+ const webComponentRef = useRef(null)
585
+
586
+ useEffect(() => {
587
+ const element = webComponentRef.current
588
+ if (!element) return
589
+
590
+ const handleUserAction = (event) => {
591
+ if (event instanceof CustomEvent) {
592
+ const action = event.detail
593
+ console.log('User action:', action.type, action.data)
594
+
595
+ // Handle different action types
596
+ switch (action.type) {
597
+ case 'select-filter':
598
+ // Handle filter selection
599
+ break
600
+ case 'show-place':
601
+ // Handle place display
602
+ break
603
+ case 'search':
604
+ // Handle search
605
+ break
606
+ // ... other cases
607
+ }
608
+ }
609
+ }
610
+
611
+ element.addEventListener('userAction', handleUserAction)
382
612
 
383
613
  return () => {
384
- element.removeEventListener('cardSelected', handleCardSelected)
614
+ element.removeEventListener('userAction', handleUserAction)
385
615
  }
386
616
  }, [])
387
617
 
@@ -401,23 +631,36 @@ import { ref, onMounted, onUnmounted } from 'vue'
401
631
 
402
632
  const webComponent = ref(null)
403
633
 
404
- const handleCardSelected = (event) => {
634
+ const handleUserAction = (event) => {
405
635
  if (event instanceof CustomEvent) {
406
- const cardId = event.detail
407
- console.log('Card selected:', cardId)
408
- // Handle card selection
636
+ const action = event.detail
637
+ console.log('User action:', action.type, action.data)
638
+
639
+ // Handle different action types
640
+ switch (action.type) {
641
+ case 'select-filter':
642
+ // Handle filter selection
643
+ break
644
+ case 'show-place':
645
+ // Handle place display
646
+ break
647
+ case 'search':
648
+ // Handle search
649
+ break
650
+ // ... other cases
651
+ }
409
652
  }
410
653
  }
411
654
 
412
655
  onMounted(() => {
413
656
  if (webComponent.value) {
414
- webComponent.value.addEventListener('cardSelected', handleCardSelected)
657
+ webComponent.value.addEventListener('userAction', handleUserAction)
415
658
  }
416
659
  })
417
660
 
418
661
  onUnmounted(() => {
419
662
  if (webComponent.value) {
420
- webComponent.value.removeEventListener('cardSelected', handleCardSelected)
663
+ webComponent.value.removeEventListener('userAction', handleUserAction)
421
664
  }
422
665
  })
423
666
  </script>
@@ -426,7 +669,7 @@ onUnmounted(() => {
426
669
  #### Angular
427
670
 
428
671
  ```typescript
429
- import { Component, ElementRef, OnInit, OnDestroy, ViewChild, AfterViewInit } from '@angular/core'
672
+ import { Component, ElementRef, OnDestroy, ViewChild, AfterViewInit } from '@angular/core'
430
673
 
431
674
  @Component({
432
675
  selector: 'app-mapvx',
@@ -436,35 +679,48 @@ export class MapvxComponent implements AfterViewInit, OnDestroy {
436
679
  @ViewChild('webComponent', { static: false }) webComponentRef!: ElementRef<HTMLElement>
437
680
 
438
681
  apiKey = 'your-api-key-here'
439
- private cardSelectedListener?: (event: Event) => void
682
+ private userActionListener?: (event: Event) => void
440
683
 
441
684
  ngAfterViewInit() {
442
- this.setupCardSelectedListener()
685
+ this.setupUserActionListener()
443
686
  }
444
687
 
445
- private setupCardSelectedListener() {
688
+ private setupUserActionListener() {
446
689
  const element = this.webComponentRef?.nativeElement
447
690
  if (!element) {
448
691
  // Retry if element is not yet available
449
- setTimeout(() => this.setupCardSelectedListener(), 100)
692
+ setTimeout(() => this.setupUserActionListener(), 100)
450
693
  return
451
694
  }
452
695
 
453
- this.cardSelectedListener = (event: Event) => {
696
+ this.userActionListener = (event: Event) => {
454
697
  if (event instanceof CustomEvent) {
455
- const cardId = event.detail as string
456
- console.log('Card selected:', cardId)
457
- // Handle card selection
698
+ const action = event.detail as { type: string; data: any }
699
+ console.log('User action:', action.type, action.data)
700
+
701
+ // Handle different action types
702
+ switch (action.type) {
703
+ case 'select-filter':
704
+ // Handle filter selection
705
+ break
706
+ case 'show-place':
707
+ // Handle place display
708
+ break
709
+ case 'search':
710
+ // Handle search
711
+ break
712
+ // ... other cases
713
+ }
458
714
  }
459
715
  }
460
716
 
461
- element.addEventListener('cardSelected', this.cardSelectedListener)
717
+ element.addEventListener('userAction', this.userActionListener)
462
718
  }
463
719
 
464
720
  ngOnDestroy() {
465
721
  const element = this.webComponentRef?.nativeElement
466
- if (element && this.cardSelectedListener) {
467
- element.removeEventListener('cardSelected', this.cardSelectedListener)
722
+ if (element && this.userActionListener) {
723
+ element.removeEventListener('userAction', this.userActionListener)
468
724
  }
469
725
  }
470
726
  }