@salesmind-ai/design-system 0.1.7 → 0.1.8

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.
@@ -567,23 +567,138 @@ var PlatformBadge = React47.forwardRef(
567
567
  }
568
568
  );
569
569
  PlatformBadge.displayName = "PlatformBadge";
570
+ var UtmContext = React47.createContext(null);
571
+
572
+ // src/web/utm/useUtmDefaults.ts
573
+ function useUtmDefaults() {
574
+ return React47.useContext(UtmContext);
575
+ }
576
+
577
+ // src/web/utm/builders.ts
578
+ var PLACEHOLDER_ORIGIN = "https://__placeholder__.internal";
579
+ function buildUtmUrl(baseUrl, params) {
580
+ const isRelative = baseUrl.startsWith("/");
581
+ let url;
582
+ try {
583
+ url = isRelative ? new URL(baseUrl, PLACEHOLDER_ORIGIN) : new URL(baseUrl);
584
+ } catch {
585
+ return baseUrl;
586
+ }
587
+ const existingParams = [];
588
+ url.searchParams.forEach((value, key) => {
589
+ existingParams.push([key, value]);
590
+ });
591
+ for (const [key] of existingParams) {
592
+ url.searchParams.delete(key);
593
+ }
594
+ for (const [key, value] of existingParams) {
595
+ if (!key.startsWith("utm_")) {
596
+ url.searchParams.set(key, value);
597
+ }
598
+ }
599
+ url.searchParams.set("utm_source", params.source);
600
+ url.searchParams.set("utm_medium", params.medium);
601
+ url.searchParams.set("utm_campaign", params.campaign);
602
+ if (params.term !== void 0) {
603
+ url.searchParams.set("utm_term", params.term);
604
+ }
605
+ if (params.content !== void 0) {
606
+ url.searchParams.set("utm_content", params.content);
607
+ }
608
+ if (isRelative) {
609
+ return url.href.replace(PLACEHOLDER_ORIGIN, "");
610
+ }
611
+ return url.href;
612
+ }
613
+
614
+ // src/web/utm/classifiers.ts
615
+ var INTERNAL_PATTERNS = [
616
+ /^\/(?!\/)/,
617
+ // Relative paths
618
+ /^https?:\/\/(www\.)?sales-mind\.ai/i,
619
+ // Marketing site
620
+ /^https?:\/\/app\.sales-mind\.ai/i,
621
+ // Web app
622
+ /^https?:\/\/apps\.sales-mind\.ai/i,
623
+ // Web app (legacy)
624
+ /^https?:\/\/meet\.sales-mind\.ai/i,
625
+ // Booking
626
+ /^https?:\/\/docs\.sales-mind\.ai/i
627
+ // Docs
628
+ ];
629
+ var SYSTEM_PATTERNS = [
630
+ /^https?:\/\/.*\/api\//i,
631
+ // API endpoints
632
+ /^https?:\/\/.*\/webhook/i,
633
+ // Webhooks
634
+ /^https?:\/\/.*\/oauth/i,
635
+ // OAuth callbacks
636
+ /^https?:\/\/.*\/callback/i,
637
+ // Callbacks
638
+ /^https?:\/\/.*\.supabase\.(co|com)/i,
639
+ // Supabase
640
+ /^https?:\/\/.*\.firebaseapp\.com/i,
641
+ // Firebase
642
+ /^https?:\/\/.*\.cloudfunctions\.net/i
643
+ // Cloud Functions
644
+ ];
645
+ var ASSET_PATTERNS = [
646
+ /\.(css|js|mjs|map|woff2?|ttf|eot|svg|png|jpe?g|gif|webp|avif|ico|pdf)(\?.*)?$/i
647
+ ];
648
+ var CONVERSION_PATTERNS = [
649
+ /^https?:\/\/(www\.)?calendly\.com/i,
650
+ /^https?:\/\/(checkout\.)?stripe\.com/i,
651
+ /^https?:\/\/buy\.stripe\.com/i,
652
+ /^https?:\/\/chromewebstore\.google\.com/i,
653
+ /^https?:\/\/meet\.sales-mind\.ai/i
654
+ ];
655
+ var PROTOCOL_EXEMPT = [
656
+ /^mailto:/i,
657
+ /^tel:/i,
658
+ /^#/,
659
+ /^javascript:/i
660
+ ];
661
+ function classifyUrl(url) {
662
+ if (PROTOCOL_EXEMPT.some((p) => p.test(url))) return "protocol";
663
+ if (ASSET_PATTERNS.some((p) => p.test(url))) return "asset";
664
+ if (SYSTEM_PATTERNS.some((p) => p.test(url))) return "system";
665
+ if (CONVERSION_PATTERNS.some((p) => p.test(url))) return "conversion";
666
+ if (INTERNAL_PATTERNS.some((p) => p.test(url))) return "internal";
667
+ return "external";
668
+ }
570
669
 
571
670
  // src/components/OutboundLink/outbound-link-utils.ts
572
- var CONSTANT_UTM_SOURCE = "salesmind";
671
+ var LEGACY_UTM_SOURCE = "salesmind";
573
672
  var EXEMPT_PATTERNS = [
574
673
  /^https?:\/\/(www\.)?(stripe\.com|checkout\.stripe\.com|paypal\.com)/i,
575
674
  /^https?:\/\/(www\.)?github\.com\/login\/oauth/i
576
675
  ];
577
676
  var isExemptUrl = (urlStr) => {
578
677
  if (urlStr.startsWith("mailto:") || urlStr.startsWith("tel:")) return true;
678
+ const classification = classifyUrl(urlStr);
679
+ if (classification === "system" || classification === "protocol" || classification === "asset") {
680
+ return true;
681
+ }
579
682
  return EXEMPT_PATTERNS.some((pattern) => pattern.test(urlStr));
580
683
  };
684
+ var appendGovernedUTMs = (href, params, preserveExisting = true) => {
685
+ try {
686
+ const url = new URL(href);
687
+ if (preserveExisting) {
688
+ const hasAll = url.searchParams.has("utm_source") && url.searchParams.has("utm_medium") && url.searchParams.has("utm_campaign");
689
+ if (hasAll) return href;
690
+ }
691
+ return buildUtmUrl(href, params);
692
+ } catch {
693
+ return href;
694
+ }
695
+ };
581
696
  var appendUTMs = (href, context, pageSlug, options) => {
582
697
  try {
583
698
  const url = new URL(href);
584
699
  const { mediumOverride = "outbound_link", campaignOverride, preserveExisting = true } = options;
585
700
  const utms = {
586
- utm_source: CONSTANT_UTM_SOURCE,
701
+ utm_source: LEGACY_UTM_SOURCE,
587
702
  utm_medium: mediumOverride,
588
703
  utm_campaign: campaignOverride || pageSlug,
589
704
  utm_content: context
@@ -610,10 +725,13 @@ var OutboundLink = React47.forwardRef(
610
725
  preserveExistingUTM = true,
611
726
  openInNewTab = true,
612
727
  disableTracking = false,
728
+ utmParams,
613
729
  onClick,
614
730
  children,
615
731
  ...props
616
732
  }, ref) => {
733
+ const contextParams = useUtmDefaults();
734
+ const resolvedUtmParams = utmParams ?? contextParams;
617
735
  let hostname = "";
618
736
  try {
619
737
  const url = new URL(href);
@@ -638,16 +756,20 @@ var OutboundLink = React47.forwardRef(
638
756
  }
639
757
  const isExempt = isExemptUrl(href) || disableTracking;
640
758
  if (isExternal && !isExempt) {
641
- const pageSlug = window.location.pathname.replace(/^\/|\/$/g, "") || "home";
642
- setFinalHref(appendUTMs(href, context, pageSlug, {
643
- mediumOverride: currentMedium,
644
- campaignOverride,
645
- preserveExisting: preserveExistingUTM
646
- }));
759
+ if (resolvedUtmParams) {
760
+ setFinalHref(appendGovernedUTMs(href, resolvedUtmParams, preserveExistingUTM));
761
+ } else {
762
+ const pageSlug = window.location.pathname.replace(/^\/|\/$/g, "") || "home";
763
+ setFinalHref(appendUTMs(href, context, pageSlug, {
764
+ mediumOverride: currentMedium,
765
+ campaignOverride,
766
+ preserveExisting: preserveExistingUTM
767
+ }));
768
+ }
647
769
  } else {
648
770
  setFinalHref(href);
649
771
  }
650
- }, [href, context, mediumOverride, campaignOverride, preserveExistingUTM, disableTracking]);
772
+ }, [href, context, mediumOverride, campaignOverride, preserveExistingUTM, disableTracking, resolvedUtmParams]);
651
773
  const handleClick = (e) => {
652
774
  if (typeof window === "undefined" || disableTracking) {
653
775
  onClick?.(e);