@mapvx/website-component 0.9.0 → 0.11.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,60 @@ 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, alias } = action.data
348
+ if (alias) {
349
+ history.pushState(
350
+ { page: 'profile', id: alias },
351
+ '',
352
+ `${location.pathname}?tenant=${alias}`,
353
+ )
354
+ } else {
355
+ history.pushState(
356
+ { page: 'profile', id: placeId },
357
+ '',
358
+ `${location.pathname}?tenant=${placeId}`,
359
+ )
360
+ }
361
+ break
362
+ }
363
+ case 'search': {
364
+ const { searchTerm } = action.data
365
+ history.pushState(
366
+ { page: 'search', term: searchTerm },
367
+ '',
368
+ `${location.pathname}?search=${encodeURIComponent(searchTerm)}`,
369
+ )
370
+ break
371
+ }
372
+ case 'select-destination': {
373
+ const { destinationId } = action.data
374
+ history.pushState(
375
+ { page: 'route', id: destinationId },
376
+ '',
377
+ `${location.pathname}?destination=${destinationId}`,
378
+ )
379
+ break
380
+ }
381
+ }
340
382
  }
341
383
  }
342
384
 
343
- element.addEventListener('cardSelected', handleCardSelected)
385
+ element.addEventListener('userAction', handleUserAction)
344
386
  }
345
387
 
346
388
  // Check if web component is already registered
@@ -370,18 +412,214 @@ function App() {
370
412
  const element = webComponentRef.current
371
413
  if (!element) return
372
414
 
373
- const handleCardSelected = (event) => {
415
+ const handleUserAction = (event) => {
416
+ if (event instanceof CustomEvent && event.detail.type === 'show-place') {
417
+ const placeId = event.detail.data.placeId
418
+ console.log('Place shown:', placeId)
419
+ // Handle place display
420
+ }
421
+ }
422
+
423
+ element.addEventListener('userAction', handleUserAction)
424
+
425
+ return () => {
426
+ element.removeEventListener('userAction', handleUserAction)
427
+ }
428
+ }, [])
429
+
430
+ return <mapvx-website ref={webComponentRef} api-key="your-api-key-here" />
431
+ }
432
+ ```
433
+
434
+ #### Vue
435
+
436
+ ```vue
437
+ <template>
438
+ <mapvx-website ref="webComponent" api-key="your-api-key-here" />
439
+ </template>
440
+
441
+ <script setup>
442
+ import { ref, onMounted, onUnmounted } from 'vue'
443
+
444
+ const webComponent = ref(null)
445
+
446
+ const handleUserAction = (event) => {
447
+ if (event instanceof CustomEvent && event.detail.type === 'show-place') {
448
+ const placeId = event.detail.data.placeId
449
+ console.log('Place shown:', placeId)
450
+ // Handle place display
451
+ }
452
+ }
453
+
454
+ onMounted(() => {
455
+ if (webComponent.value) {
456
+ webComponent.value.addEventListener('userAction', handleUserAction)
457
+ }
458
+ })
459
+
460
+ onUnmounted(() => {
461
+ if (webComponent.value) {
462
+ webComponent.value.removeEventListener('userAction', handleUserAction)
463
+ }
464
+ })
465
+ </script>
466
+ ```
467
+
468
+ #### Angular
469
+
470
+ ```typescript
471
+ import { Component, ElementRef, OnDestroy, ViewChild, AfterViewInit } from '@angular/core'
472
+
473
+ @Component({
474
+ selector: 'app-mapvx',
475
+ template: ` <mapvx-website #webComponent [attr.api-key]="apiKey" /> `,
476
+ })
477
+ export class MapvxComponent implements AfterViewInit, OnDestroy {
478
+ @ViewChild('webComponent', { static: false }) webComponentRef!: ElementRef<HTMLElement>
479
+
480
+ apiKey = 'your-api-key-here'
481
+ private userActionListener?: (event: Event) => void
482
+
483
+ ngAfterViewInit() {
484
+ this.setupUserActionListener()
485
+ }
486
+
487
+ private setupUserActionListener() {
488
+ const element = this.webComponentRef?.nativeElement
489
+ if (!element) {
490
+ // Retry if element is not yet available
491
+ setTimeout(() => this.setupUserActionListener(), 100)
492
+ return
493
+ }
494
+
495
+ this.userActionListener = (event: Event) => {
374
496
  if (event instanceof CustomEvent) {
375
- const cardId = event.detail
376
- console.log('Card selected:', cardId)
377
- // Handle card selection
497
+ const action = event.detail as { type: string; data: any }
498
+ if (action.type === 'show-place') {
499
+ const placeId = action.data.placeId
500
+ console.log('Place shown:', placeId)
501
+ // Handle place display
502
+ }
378
503
  }
379
504
  }
380
505
 
381
- element.addEventListener('cardSelected', handleCardSelected)
506
+ element.addEventListener('userAction', this.userActionListener)
507
+ }
508
+
509
+ ngOnDestroy() {
510
+ const element = this.webComponentRef?.nativeElement
511
+ if (element && this.userActionListener) {
512
+ element.removeEventListener('userAction', this.userActionListener)
513
+ }
514
+ }
515
+ }
516
+ ```
517
+
518
+ ### User Action Event
519
+
520
+ The `userAction` event provides detailed information about user interactions within the component. The event detail contains an object with `type` and `data` properties.
521
+
522
+ #### UserAction Types
523
+
524
+ | Type | Description | Data Structure |
525
+ | -------------------- | ------------------------------------------ | --------------------------------------- | ------------ |
526
+ | `select-filter` | Emitted when a filter is selected | `{ filter: string }` |
527
+ | `show-place` | Emitted when a place is displayed | `{ placeId: string, alias: string | undefined }` |
528
+ | `select-destination` | Emitted when a destination is selected | `{ destinationId: string, alias: string | undefined }` |
529
+ | `search` | Emitted when a search is performed | `{ searchTerm: string }` |
530
+ | `return-to-home` | Emitted when user returns to the home view | `{ filter: string }` |
531
+
532
+ #### UserAction Usage Examples
533
+
534
+ #### Vanilla JavaScript
535
+
536
+ ```javascript
537
+ // Wait for the web component to be registered
538
+ function setupUserActionListener() {
539
+ const element = document.querySelector('mapvx-website')
540
+ if (element) {
541
+ element.addEventListener('userAction', (event) => {
542
+ if (event instanceof CustomEvent) {
543
+ const action = event.detail
544
+ console.log('User action:', action.type, action.data)
545
+
546
+ // Handle different action types
547
+ switch (action.type) {
548
+ case 'select-filter':
549
+ console.log('Filter selected:', action.data.filter)
550
+ break
551
+ case 'show-place':
552
+ console.log('Place shown:', action.data.placeId)
553
+ break
554
+ case 'select-destination':
555
+ console.log('Destination selected:', action.data.destinationId)
556
+ break
557
+ case 'search':
558
+ console.log('Search performed:', action.data.searchTerm)
559
+ break
560
+ case 'return-to-home':
561
+ console.log('Returned to home with filter:', action.data.filter)
562
+ break
563
+ }
564
+ }
565
+ })
566
+ } else {
567
+ // Retry if element is not yet available
568
+ setTimeout(setupUserActionListener, 100)
569
+ }
570
+ }
571
+
572
+ // Check if web component is already registered
573
+ if (customElements.get('mapvx-website')) {
574
+ setupUserActionListener()
575
+ } else {
576
+ // Wait for registration
577
+ const checkInterval = setInterval(() => {
578
+ if (customElements.get('mapvx-website')) {
579
+ setupUserActionListener()
580
+ clearInterval(checkInterval)
581
+ }
582
+ }, 100)
583
+ }
584
+ ```
585
+
586
+ #### React
587
+
588
+ ```jsx
589
+ import { useEffect, useRef } from 'react'
590
+
591
+ function App() {
592
+ const webComponentRef = useRef(null)
593
+
594
+ useEffect(() => {
595
+ const element = webComponentRef.current
596
+ if (!element) return
597
+
598
+ const handleUserAction = (event) => {
599
+ if (event instanceof CustomEvent) {
600
+ const action = event.detail
601
+ console.log('User action:', action.type, action.data)
602
+
603
+ // Handle different action types
604
+ switch (action.type) {
605
+ case 'select-filter':
606
+ // Handle filter selection
607
+ break
608
+ case 'show-place':
609
+ // Handle place display
610
+ break
611
+ case 'search':
612
+ // Handle search
613
+ break
614
+ // ... other cases
615
+ }
616
+ }
617
+ }
618
+
619
+ element.addEventListener('userAction', handleUserAction)
382
620
 
383
621
  return () => {
384
- element.removeEventListener('cardSelected', handleCardSelected)
622
+ element.removeEventListener('userAction', handleUserAction)
385
623
  }
386
624
  }, [])
387
625
 
@@ -401,23 +639,36 @@ import { ref, onMounted, onUnmounted } from 'vue'
401
639
 
402
640
  const webComponent = ref(null)
403
641
 
404
- const handleCardSelected = (event) => {
642
+ const handleUserAction = (event) => {
405
643
  if (event instanceof CustomEvent) {
406
- const cardId = event.detail
407
- console.log('Card selected:', cardId)
408
- // Handle card selection
644
+ const action = event.detail
645
+ console.log('User action:', action.type, action.data)
646
+
647
+ // Handle different action types
648
+ switch (action.type) {
649
+ case 'select-filter':
650
+ // Handle filter selection
651
+ break
652
+ case 'show-place':
653
+ // Handle place display
654
+ break
655
+ case 'search':
656
+ // Handle search
657
+ break
658
+ // ... other cases
659
+ }
409
660
  }
410
661
  }
411
662
 
412
663
  onMounted(() => {
413
664
  if (webComponent.value) {
414
- webComponent.value.addEventListener('cardSelected', handleCardSelected)
665
+ webComponent.value.addEventListener('userAction', handleUserAction)
415
666
  }
416
667
  })
417
668
 
418
669
  onUnmounted(() => {
419
670
  if (webComponent.value) {
420
- webComponent.value.removeEventListener('cardSelected', handleCardSelected)
671
+ webComponent.value.removeEventListener('userAction', handleUserAction)
421
672
  }
422
673
  })
423
674
  </script>
@@ -426,7 +677,7 @@ onUnmounted(() => {
426
677
  #### Angular
427
678
 
428
679
  ```typescript
429
- import { Component, ElementRef, OnInit, OnDestroy, ViewChild, AfterViewInit } from '@angular/core'
680
+ import { Component, ElementRef, OnDestroy, ViewChild, AfterViewInit } from '@angular/core'
430
681
 
431
682
  @Component({
432
683
  selector: 'app-mapvx',
@@ -436,35 +687,48 @@ export class MapvxComponent implements AfterViewInit, OnDestroy {
436
687
  @ViewChild('webComponent', { static: false }) webComponentRef!: ElementRef<HTMLElement>
437
688
 
438
689
  apiKey = 'your-api-key-here'
439
- private cardSelectedListener?: (event: Event) => void
690
+ private userActionListener?: (event: Event) => void
440
691
 
441
692
  ngAfterViewInit() {
442
- this.setupCardSelectedListener()
693
+ this.setupUserActionListener()
443
694
  }
444
695
 
445
- private setupCardSelectedListener() {
696
+ private setupUserActionListener() {
446
697
  const element = this.webComponentRef?.nativeElement
447
698
  if (!element) {
448
699
  // Retry if element is not yet available
449
- setTimeout(() => this.setupCardSelectedListener(), 100)
700
+ setTimeout(() => this.setupUserActionListener(), 100)
450
701
  return
451
702
  }
452
703
 
453
- this.cardSelectedListener = (event: Event) => {
704
+ this.userActionListener = (event: Event) => {
454
705
  if (event instanceof CustomEvent) {
455
- const cardId = event.detail as string
456
- console.log('Card selected:', cardId)
457
- // Handle card selection
706
+ const action = event.detail as { type: string; data: any }
707
+ console.log('User action:', action.type, action.data)
708
+
709
+ // Handle different action types
710
+ switch (action.type) {
711
+ case 'select-filter':
712
+ // Handle filter selection
713
+ break
714
+ case 'show-place':
715
+ // Handle place display
716
+ break
717
+ case 'search':
718
+ // Handle search
719
+ break
720
+ // ... other cases
721
+ }
458
722
  }
459
723
  }
460
724
 
461
- element.addEventListener('cardSelected', this.cardSelectedListener)
725
+ element.addEventListener('userAction', this.userActionListener)
462
726
  }
463
727
 
464
728
  ngOnDestroy() {
465
729
  const element = this.webComponentRef?.nativeElement
466
- if (element && this.cardSelectedListener) {
467
- element.removeEventListener('cardSelected', this.cardSelectedListener)
730
+ if (element && this.userActionListener) {
731
+ element.removeEventListener('userAction', this.userActionListener)
468
732
  }
469
733
  }
470
734
  }