@axos-web-dev/shared-components 2.2.19 → 2.2.20

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.
@@ -12,9 +12,10 @@ import '../assets/Modal/Modal.css';import '../assets/VideoWrapper/VideoWrapper.c
12
12
  /* empty css */
13
13
  /* empty css */
14
14
  /* empty css */
15
+ import { handleAnchorClick } from "../utils/appendQueryParams.js";
15
16
  import { getVariant } from "../utils/getVariant.js";
16
- import clsx from "clsx";
17
17
  import { useState, createElement } from "react";
18
+ import clsx from "clsx";
18
19
  import "../AlertBanner/AlertBanner.css.js";
19
20
  import "../Article/Article.css.js";
20
21
  import { button } from "./Button.css.js";
@@ -163,8 +164,9 @@ const Button = ({
163
164
  setTargetLinkUrl(targetUrl);
164
165
  return;
165
166
  }
166
- e.preventDefault();
167
167
  const resolved = resolveUrl(targetUrl);
168
+ if (handleAnchorClick(e, resolved)) return;
169
+ e.preventDefault();
168
170
  if (newTab) {
169
171
  window.open(resolved, "_blank");
170
172
  } else {
@@ -18,6 +18,7 @@ import { Interstitial } from "../Interstitial/Interstitial.js";
18
18
  import { chevron, chevron_wrapper } from "./Chevron.css.js";
19
19
  /* empty css */
20
20
  import { useGlobalContext } from "../Modal/contextApi/store.js";
21
+ import { handleAnchorClick } from "../utils/appendQueryParams.js";
21
22
  import clsx from "clsx";
22
23
  import "../Button/Button.css.js";
23
24
  import "react-use";
@@ -179,7 +180,9 @@ const Chevron = ({
179
180
  e.preventDefault();
180
181
  setOpenModal(external_link);
181
182
  setTargetLinkUrl(targetUrl);
183
+ return;
182
184
  }
185
+ handleAnchorClick(e, resolveUrl(targetUrl));
183
186
  }
184
187
  } : backFunction;
185
188
  return /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -10,8 +10,8 @@ import '../../assets/VideoWrapper/VideoWrapper.css';import '../../assets/Topical
10
10
  /* empty css */
11
11
  /* empty css */
12
12
  /* empty css */
13
- import "clsx";
14
13
  import "react";
14
+ import "clsx";
15
15
  import "../../Chevron/Chevron.css.js";
16
16
  import "../../AlertBanner/AlertBanner.css.js";
17
17
  import "../../Article/Article.css.js";
@@ -24,7 +24,9 @@ import '../assets/VideoWrapper/VideoWrapper.css';import '../assets/TopicalNavSet
24
24
  /* empty css */
25
25
  import "../Accordion/Accordion.js";
26
26
  import "../Accordion/Accordion.css.js";
27
+ import { z } from "zod";
27
28
  import { getVariant } from "../utils/getVariant.js";
29
+ import { useCachedEmailValidator } from "../utils/useCachedValidators.js";
28
30
  import clsx from "clsx";
29
31
  import "react";
30
32
  import "../Chevron/Chevron.css.js";
@@ -35,8 +37,6 @@ import "../Button/Button.css.js";
35
37
  import "react-use";
36
38
  import "../ArticlesSet/ArticlesSet.css.js";
37
39
  import "../IconBillboard/IconBillboard.css.js";
38
- import { z } from "zod";
39
- import { useCachedEmailValidator } from "../utils/useCachedValidators.js";
40
40
  import "../Calculators/calculator.css.js";
41
41
  import "../Calculators/AnnualFeeCalculator/AnnualFeeCalculator.css.js";
42
42
  import "../Calculators/ApyCalculator/ApyCalculator.css.js";
@@ -24,7 +24,9 @@ import '../assets/VideoWrapper/VideoWrapper.css';import '../assets/TopicalNavSet
24
24
  /* empty css */
25
25
  import "../Accordion/Accordion.js";
26
26
  import "../Accordion/Accordion.css.js";
27
+ import { z } from "zod";
27
28
  import { getVariant } from "../utils/getVariant.js";
29
+ import { useCachedEmailValidator } from "../utils/useCachedValidators.js";
28
30
  import clsx from "clsx";
29
31
  import "react";
30
32
  import "../Chevron/Chevron.css.js";
@@ -35,8 +37,6 @@ import "../Button/Button.css.js";
35
37
  import "react-use";
36
38
  import "../ArticlesSet/ArticlesSet.css.js";
37
39
  import "../IconBillboard/IconBillboard.css.js";
38
- import { z } from "zod";
39
- import { useCachedEmailValidator } from "../utils/useCachedValidators.js";
40
40
  import "../Calculators/calculator.css.js";
41
41
  import "../Calculators/AnnualFeeCalculator/AnnualFeeCalculator.css.js";
42
42
  import "../Calculators/ApyCalculator/ApyCalculator.css.js";
@@ -24,7 +24,9 @@ import '../assets/VideoWrapper/VideoWrapper.css';import '../assets/TopicalNavSet
24
24
  /* empty css */
25
25
  import "../Accordion/Accordion.js";
26
26
  import "../Accordion/Accordion.css.js";
27
+ import { z } from "zod";
27
28
  import { getVariant } from "../utils/getVariant.js";
29
+ import { useCachedEmailValidator } from "../utils/useCachedValidators.js";
28
30
  import clsx from "clsx";
29
31
  import "react";
30
32
  import "../Chevron/Chevron.css.js";
@@ -35,8 +37,6 @@ import "../Button/Button.css.js";
35
37
  import "react-use";
36
38
  import "../ArticlesSet/ArticlesSet.css.js";
37
39
  import "../IconBillboard/IconBillboard.css.js";
38
- import { z } from "zod";
39
- import { useCachedEmailValidator } from "../utils/useCachedValidators.js";
40
40
  import "../Calculators/calculator.css.js";
41
41
  import "../Calculators/AnnualFeeCalculator/AnnualFeeCalculator.css.js";
42
42
  import "../Calculators/ApyCalculator/ApyCalculator.css.js";
@@ -24,7 +24,9 @@ import '../assets/VideoWrapper/VideoWrapper.css';import '../assets/TopicalNavSet
24
24
  /* empty css */
25
25
  import "../Accordion/Accordion.js";
26
26
  import "../Accordion/Accordion.css.js";
27
+ import { z } from "zod";
27
28
  import { getVariant } from "../utils/getVariant.js";
29
+ import { useCachedEmailValidator } from "../utils/useCachedValidators.js";
28
30
  import clsx from "clsx";
29
31
  import "react";
30
32
  import "../Chevron/Chevron.css.js";
@@ -35,8 +37,6 @@ import "../Button/Button.css.js";
35
37
  import "react-use";
36
38
  import "../ArticlesSet/ArticlesSet.css.js";
37
39
  import "../IconBillboard/IconBillboard.css.js";
38
- import { z } from "zod";
39
- import { useCachedEmailValidator } from "../utils/useCachedValidators.js";
40
40
  import "../Calculators/calculator.css.js";
41
41
  import "../Calculators/AnnualFeeCalculator/AnnualFeeCalculator.css.js";
42
42
  import "../Calculators/ApyCalculator/ApyCalculator.css.js";
@@ -24,7 +24,10 @@ import '../assets/VideoWrapper/VideoWrapper.css';import '../assets/TopicalNavSet
24
24
  /* empty css */
25
25
  import "../Accordion/Accordion.js";
26
26
  import "../Accordion/Accordion.css.js";
27
+ import { z } from "zod";
28
+ import { associatedEmail } from "../utils/EverestValidity.js";
27
29
  import { getVariant } from "../utils/getVariant.js";
30
+ import { useCachedEmailValidator } from "../utils/useCachedValidators.js";
28
31
  import clsx from "clsx";
29
32
  import "react";
30
33
  import "../Chevron/Chevron.css.js";
@@ -35,9 +38,6 @@ import "../Button/Button.css.js";
35
38
  import "react-use";
36
39
  import "../ArticlesSet/ArticlesSet.css.js";
37
40
  import "../IconBillboard/IconBillboard.css.js";
38
- import { z } from "zod";
39
- import { associatedEmail } from "../utils/EverestValidity.js";
40
- import { useCachedEmailValidator } from "../utils/useCachedValidators.js";
41
41
  import "../Calculators/calculator.css.js";
42
42
  import "../Calculators/AnnualFeeCalculator/AnnualFeeCalculator.css.js";
43
43
  import "../Calculators/ApyCalculator/ApyCalculator.css.js";
@@ -24,7 +24,9 @@ import '../assets/VideoWrapper/VideoWrapper.css';import '../assets/TopicalNavSet
24
24
  /* empty css */
25
25
  import "../Accordion/Accordion.js";
26
26
  import "../Accordion/Accordion.css.js";
27
+ import { z } from "zod";
27
28
  import { getVariant } from "../utils/getVariant.js";
29
+ import { useCachedEmailValidator } from "../utils/useCachedValidators.js";
28
30
  import clsx from "clsx";
29
31
  import "react";
30
32
  import "../Chevron/Chevron.css.js";
@@ -35,8 +37,6 @@ import "../Button/Button.css.js";
35
37
  import "react-use";
36
38
  import "../ArticlesSet/ArticlesSet.css.js";
37
39
  import "../IconBillboard/IconBillboard.css.js";
38
- import { z } from "zod";
39
- import { useCachedEmailValidator } from "../utils/useCachedValidators.js";
40
40
  import "../Calculators/calculator.css.js";
41
41
  import "../Calculators/AnnualFeeCalculator/AnnualFeeCalculator.css.js";
42
42
  import "../Calculators/ApyCalculator/ApyCalculator.css.js";
@@ -11,12 +11,12 @@ import '../assets/Modal/Modal.css';import '../assets/VideoWrapper/VideoWrapper.c
11
11
  /* empty css */
12
12
  /* empty css */
13
13
  /* empty css */
14
- import clsx from "clsx";
15
14
  import "react";
15
+ import { isPhoneLink, isEmailLink } from "../utils/validateExternalLinks.js";
16
+ import clsx from "clsx";
16
17
  import "../AlertBanner/AlertBanner.css.js";
17
18
  import "../Article/Article.css.js";
18
19
  import "../IconBillboard/IconBillboard.css.js";
19
- import { isPhoneLink, isEmailLink } from "../utils/validateExternalLinks.js";
20
20
  /* empty css */
21
21
  /* empty css */
22
22
  import "../Interstitial/Interstitial-variants.css.js";
@@ -10,8 +10,8 @@ import '../assets/Modal/Modal.css';import '../assets/VideoWrapper/VideoWrapper.c
10
10
  /* empty css */
11
11
  /* empty css */
12
12
  /* empty css */
13
- import "clsx";
14
13
  import "react";
14
+ import "clsx";
15
15
  import "../AlertBanner/AlertBanner.css.js";
16
16
  import "../Article/Article.css.js";
17
17
  import "../IconBillboard/IconBillboard.css.js";
@@ -10,8 +10,8 @@ import '../assets/VideoWrapper/VideoWrapper.css';import '../assets/TopicalNavSet
10
10
  /* empty css */
11
11
  /* empty css */
12
12
  /* empty css */
13
- import "clsx";
14
13
  import "react";
14
+ import "clsx";
15
15
  import "../AlertBanner/AlertBanner.css.js";
16
16
  import "../Article/Article.css.js";
17
17
  import { Button } from "../Button/Button.js";
@@ -2,9 +2,22 @@
2
2
  import { jsxs, jsx } from "react/jsx-runtime";
3
3
  import { Modal } from "../Modal.js";
4
4
  import { findMoreAxosDomains, isAllowedUrl } from "../../utils/allowedAxosDomains.js";
5
- import { createContext, useState, useEffect, useCallback, useContext } from "react";
5
+ import { filterParams, appendQueryParams } from "../../utils/appendQueryParams.js";
6
+ import { createContext, useState, useRef, useEffect, useCallback, useContext } from "react";
6
7
  import { validateLink, shortUrl } from "../../utils/validateExternalLinks.js";
8
+ import { hasNoUtms, getTealiumOrganicFallback } from "../../utils/tealiumOrganicFallback.js";
7
9
  const noopResolver = (url) => url;
10
+ const ORGANIC_UTM_HOSTNAMES = [/^secure(\.[a-z]+)?\.axosbank\.com$/];
11
+ const isOrganicUtmTarget = (url) => {
12
+ try {
13
+ const parsed = new URL(url, window.location.origin);
14
+ return ORGANIC_UTM_HOSTNAMES.some(
15
+ (pattern) => pattern.test(parsed.hostname)
16
+ );
17
+ } catch {
18
+ return false;
19
+ }
20
+ };
8
21
  const GlobalContext = createContext({
9
22
  targetLinkUrl: "",
10
23
  setTargetLinkUrl: () => "",
@@ -26,41 +39,83 @@ const GlobalContextProvider = ({
26
39
  const [domains] = useState(initialDomains);
27
40
  const [domainsLoading] = useState(false);
28
41
  const [domainsError] = useState(null);
29
- const [currentSearch, setCurrentSearch] = useState(
30
- typeof window !== "undefined" ? window.location.search.slice(1) : ""
42
+ const persistedSearchRef = useRef(
43
+ typeof window !== "undefined" ? window.location.search : ""
31
44
  );
32
45
  useEffect(() => {
46
+ const originalPush = window.history.pushState.bind(window.history);
33
47
  const originalReplace = window.history.replaceState.bind(window.history);
34
- window.history.replaceState = (...args) => {
35
- originalReplace(...args);
36
- setCurrentSearch(window.location.search.slice(1));
48
+ let rafId;
49
+ const refreshLinkParams = () => {
50
+ cancelAnimationFrame(rafId);
51
+ rafId = requestAnimationFrame(
52
+ () => appendQueryParams(persistedSearchRef.current)
53
+ );
54
+ };
55
+ const mergePersistedParams = (url) => {
56
+ if (!persistedSearchRef.current || !url) return url;
57
+ try {
58
+ const parsed = new URL(String(url), window.location.href);
59
+ const persisted = new URLSearchParams(persistedSearchRef.current);
60
+ for (const [key, value] of persisted.entries()) {
61
+ if (!parsed.searchParams.has(key)) {
62
+ parsed.searchParams.set(key, value);
63
+ }
64
+ }
65
+ return parsed.toString();
66
+ } catch {
67
+ return url;
68
+ }
69
+ };
70
+ window.history.pushState = (state, unused, url) => {
71
+ originalPush(state, unused, url);
72
+ if (window.location.search) {
73
+ persistedSearchRef.current = window.location.search;
74
+ }
37
75
  };
38
- setCurrentSearch(window.location.search.slice(1));
76
+ window.history.replaceState = (state, unused, url) => {
77
+ const mergedUrl = mergePersistedParams(url);
78
+ originalReplace(state, unused, mergedUrl);
79
+ if (window.location.search) {
80
+ persistedSearchRef.current = window.location.search;
81
+ }
82
+ };
83
+ const observer = new MutationObserver(refreshLinkParams);
84
+ observer.observe(document.body, { childList: true, subtree: true });
85
+ window.addEventListener("popstate", refreshLinkParams);
39
86
  return () => {
87
+ window.history.pushState = originalPush;
40
88
  window.history.replaceState = originalReplace;
89
+ window.removeEventListener("popstate", refreshLinkParams);
90
+ observer.disconnect();
91
+ cancelAnimationFrame(rafId);
41
92
  };
42
93
  }, []);
43
94
  const resolveUrl = useCallback(
44
95
  (url) => {
96
+ if (!url) return url;
45
97
  const resolved = findMoreAxosDomains(url, domains);
46
- if (!currentSearch || !url) return resolved;
47
98
  if (resolved.startsWith("#")) return resolved;
48
99
  try {
49
- const resolvedUrl = new URL(resolved, window.location.origin);
50
- const existingParams = new URLSearchParams(resolvedUrl.search);
51
- const pageParams = new URLSearchParams(currentSearch);
52
- for (const [key, value] of pageParams.entries()) {
53
- if (!existingParams.has(key)) {
54
- existingParams.append(key, value);
100
+ const resolvedUrl = new URL(resolved, window.location.href);
101
+ if (isOrganicUtmTarget(resolved) && hasNoUtms(new URLSearchParams(resolvedUrl.search))) {
102
+ const fallback = getTealiumOrganicFallback();
103
+ if (fallback) {
104
+ resolvedUrl.searchParams.set("utm_source", fallback.utm_source);
105
+ resolvedUrl.searchParams.set("utm_medium", fallback.utm_medium);
106
+ resolvedUrl.searchParams.set("utm_campaign", fallback.utm_campaign);
107
+ return filterParams(
108
+ resolvedUrl.toString(),
109
+ persistedSearchRef.current
110
+ );
55
111
  }
56
112
  }
57
- resolvedUrl.search = existingParams.toString();
58
- return resolvedUrl.toString();
59
113
  } catch {
60
114
  return resolved;
61
115
  }
116
+ return filterParams(resolved, persistedSearchRef.current);
62
117
  },
63
- [domains, currentSearch]
118
+ [domains]
64
119
  );
65
120
  const isAllowedUrl$1 = useCallback(
66
121
  (url) => isAllowedUrl(url, domains),
@@ -10,13 +10,13 @@ import '../../assets/VideoWrapper/VideoWrapper.css';import '../../assets/Topical
10
10
  /* empty css */
11
11
  /* empty css */
12
12
  /* empty css */
13
- import "clsx";
13
+ import { appendQueryParams } from "../../utils/appendQueryParams.js";
14
14
  import { useState, useRef, useEffect } from "react";
15
+ import "clsx";
15
16
  import "../../Chevron/Chevron.css.js";
16
17
  import "../../AlertBanner/AlertBanner.css.js";
17
18
  import "../../Article/Article.css.js";
18
19
  import "../../IconBillboard/IconBillboard.css.js";
19
- import { appendQueryParams } from "../../utils/appendQueryParams.js";
20
20
  /* empty css */
21
21
  /* empty css */
22
22
  import "../../Interstitial/Interstitial-variants.css.js";
@@ -14,13 +14,13 @@ import '../../assets/VideoWrapper/VideoWrapper.css';import '../../assets/Topical
14
14
  /* empty css */
15
15
  /* empty css */
16
16
  /* empty css */
17
+ import { appendQueryParams } from "../../utils/appendQueryParams.js";
17
18
  import clsx from "clsx";
18
19
  import "../../Chevron/Chevron.css.js";
19
20
  import "../../AlertBanner/AlertBanner.css.js";
20
21
  import "../../Article/Article.css.js";
21
22
  import "../../ArticlesSet/ArticlesSet.css.js";
22
23
  import "../../IconBillboard/IconBillboard.css.js";
23
- import { appendQueryParams } from "../../utils/appendQueryParams.js";
24
24
  import "../../Calculators/calculator.css.js";
25
25
  import "../../Calculators/AnnualFeeCalculator/AnnualFeeCalculator.css.js";
26
26
  import "../../Calculators/ApyCalculator/ApyCalculator.css.js";
@@ -14,13 +14,13 @@ import '../../assets/VideoWrapper/VideoWrapper.css';import '../../assets/Topical
14
14
  /* empty css */
15
15
  /* empty css */
16
16
  /* empty css */
17
+ import { appendQueryParams } from "../../utils/appendQueryParams.js";
17
18
  import clsx from "clsx";
18
19
  import "../../Chevron/Chevron.css.js";
19
20
  import "../../AlertBanner/AlertBanner.css.js";
20
21
  import "../../Article/Article.css.js";
21
22
  import "../../ArticlesSet/ArticlesSet.css.js";
22
23
  import "../../IconBillboard/IconBillboard.css.js";
23
- import { appendQueryParams } from "../../utils/appendQueryParams.js";
24
24
  import "../../Calculators/calculator.css.js";
25
25
  import "../../Calculators/AnnualFeeCalculator/AnnualFeeCalculator.css.js";
26
26
  import "../../Calculators/ApyCalculator/ApyCalculator.css.js";
@@ -10,13 +10,13 @@ import '../assets/VideoWrapper/VideoWrapper.css';import '../assets/TopicalNavSet
10
10
  /* empty css */
11
11
  /* empty css */
12
12
  /* empty css */
13
- import "clsx";
13
+ import { appendQueryParams } from "../utils/appendQueryParams.js";
14
14
  import { useState, useEffect } from "react";
15
+ import "clsx";
15
16
  import "../Chevron/Chevron.css.js";
16
17
  import "../AlertBanner/AlertBanner.css.js";
17
18
  import "../Article/Article.css.js";
18
19
  import "../IconBillboard/IconBillboard.css.js";
19
- import { appendQueryParams } from "../utils/appendQueryParams.js";
20
20
  /* empty css */
21
21
  /* empty css */
22
22
  import "../Interstitial/Interstitial-variants.css.js";
@@ -10,8 +10,9 @@ import '../assets/VideoWrapper/VideoWrapper.css';import '../assets/TopicalNavSet
10
10
  /* empty css */
11
11
  /* empty css */
12
12
  /* empty css */
13
- import clsx from "clsx";
13
+ import { appendQueryParams } from "../utils/appendQueryParams.js";
14
14
  import { useRef, useState, useEffect } from "react";
15
+ import clsx from "clsx";
15
16
  import "../Chevron/Chevron.css.js";
16
17
  import "../AlertBanner/AlertBanner.css.js";
17
18
  import "../Article/Article.css.js";
@@ -20,7 +21,6 @@ import "../Button/Button.css.js";
20
21
  import { useClickAway } from "react-use";
21
22
  import "../ArticlesSet/ArticlesSet.css.js";
22
23
  import "../IconBillboard/IconBillboard.css.js";
23
- import { appendQueryParams } from "../utils/appendQueryParams.js";
24
24
  import "../Calculators/calculator.css.js";
25
25
  import "../Calculators/AnnualFeeCalculator/AnnualFeeCalculator.css.js";
26
26
  import "../Calculators/ApyCalculator/ApyCalculator.css.js";
@@ -9,8 +9,8 @@ import '../assets/VideoWrapper/VideoWrapper.css';import '../assets/TopicalNavSet
9
9
  /* empty css */
10
10
  /* empty css */
11
11
  /* empty css */
12
- import "clsx";
13
12
  import "react";
13
+ import "clsx";
14
14
  import "../Chevron/Chevron.css.js";
15
15
  import "../AlertBanner/AlertBanner.css.js";
16
16
  import "../Article/Article.css.js";
@@ -10,8 +10,8 @@ import '../assets/TopicalNavSet/TopicalNavSet.css';import '../assets/TopicalNavI
10
10
  /* empty css */
11
11
  /* empty css */
12
12
  import { getVariant } from "../utils/getVariant.js";
13
- import clsx from "clsx";
14
13
  import "react";
14
+ import clsx from "clsx";
15
15
  import "../Chevron/Chevron.css.js";
16
16
  import "../AlertBanner/AlertBanner.css.js";
17
17
  import "../Article/Article.css.js";
package/dist/main.js CHANGED
@@ -211,7 +211,7 @@ import { VideoWrapper } from "./VideoWrapper/index.js";
211
211
  import { Tab } from "./Tab/Tab.js";
212
212
  import { TabContainer } from "./Tab/TabContainer.js";
213
213
  import { findMoreAxosDomains, getMoreDomains, isAllowedUrl } from "./utils/allowedAxosDomains.js";
214
- import { appendQueryParams } from "./utils/appendQueryParams.js";
214
+ import { appendQueryParams, filterParams, handleAnchorClick } from "./utils/appendQueryParams.js";
215
215
  import { createCachedEmailValidator } from "./utils/emailValidation.js";
216
216
  import { associatedEmail } from "./utils/EverestValidity.js";
217
217
  import { getVariant, getVariantWithRegex } from "./utils/getVariant.js";
@@ -583,6 +583,7 @@ export {
583
583
  featured_subgrid_title,
584
584
  featured_supertag,
585
585
  featured_title,
586
+ filterParams,
586
587
  findMoreAxosDomains,
587
588
  flexColumn,
588
589
  footerDisclosure,
@@ -612,6 +613,7 @@ export {
612
613
  getMoreDomains,
613
614
  getVariant,
614
615
  getVariantWithRegex,
616
+ handleAnchorClick,
615
617
  header,
616
618
  headerAccordion,
617
619
  headerCell,
@@ -1 +1,3 @@
1
- export declare const appendQueryParams: () => void;
1
+ export declare const filterParams: (href: string, currentSearch?: string) => string;
2
+ export declare const handleAnchorClick: (e: MouseEvent | React.MouseEvent, resolved: string) => boolean;
3
+ export declare const appendQueryParams: (currentSearch?: string) => void;
@@ -1,76 +1,76 @@
1
- const appendQueryParams = () => {
2
- const currentOrigin = window.location.origin;
3
- const currentPathname = window.location.pathname;
4
- const filterParams = (href, currentSearch) => {
5
- try {
6
- const search = currentSearch ?? window.location.search;
7
- const searchParams = new URLSearchParams(search);
8
- const base = window.location.origin + window.location.pathname + window.location.search;
9
- const url = new URL(href, base);
10
- const existingParams = new URLSearchParams(url.search);
11
- const newParams = new URLSearchParams();
12
- const addedKeys = /* @__PURE__ */ new Set();
13
- for (const key of existingParams.keys()) {
14
- addedKeys.add(decodeURIComponent(key));
15
- }
1
+ const filterParams = (href, currentSearch) => {
2
+ if (typeof window === "undefined") return href;
3
+ try {
4
+ if (!href || href.startsWith("tel:") || href.startsWith("mailto:") || href === "#" || href === "") {
5
+ return href;
6
+ }
7
+ const search = currentSearch ?? window.location.search;
8
+ const searchParams = new URLSearchParams(search);
9
+ const base = window.location.href;
10
+ const url = new URL(href, base);
11
+ if (url.pathname === window.location.pathname && url.hash) {
12
+ const existingInHash = new URLSearchParams(url.search);
16
13
  for (const [key, value] of searchParams.entries()) {
17
- const decodedKey = decodeURIComponent(key);
18
- const decodedValue = decodeURIComponent(value);
19
- const lowerKey = decodedKey.toLowerCase();
20
- if (!addedKeys.has(lowerKey) && !decodedKey.includes("[]")) {
21
- newParams.append(lowerKey, decodedValue);
22
- addedKeys.add(lowerKey);
23
- } else if (decodedKey.includes("[]")) {
24
- const existingValues = existingParams.getAll(key).map(decodeURIComponent);
25
- if (!existingValues.includes(decodedValue)) {
26
- newParams.append(decodedKey, decodedValue);
27
- }
14
+ const decodedKey = decodeURIComponent(key).toLowerCase();
15
+ if (!existingInHash.has(decodedKey) && !decodedKey.includes("[]")) {
16
+ existingInHash.set(decodedKey, decodeURIComponent(value));
28
17
  }
29
18
  }
30
- const mergedParams = new URLSearchParams(existingParams);
31
- newParams.forEach((value, key) => mergedParams.append(key, value));
32
- return `${url.origin}${url.pathname}?${mergedParams.toString()}${url.hash}`;
33
- } catch (e) {
34
- console.error(e);
35
- return href;
19
+ return `?${existingInHash.toString()}${url.hash}`;
36
20
  }
37
- };
38
- const handleSamePageClick = (e) => {
39
- const anchor = e.target?.closest?.("a[href]");
40
- if (!anchor || anchor.classList.contains("ext-link"))
41
- return;
42
- const href = anchor.getAttribute("href")?.trim();
43
- if (!href || href.startsWith("tel:") || href.startsWith("mailto:") || href === "#" || href === "" || href.startsWith("#"))
44
- return;
45
- const base = window.location.origin + window.location.pathname + window.location.search;
46
- const url = new URL(href, base);
47
- if (url.origin !== currentOrigin || url.pathname !== currentPathname)
48
- return;
49
- e.preventDefault();
50
- e.stopImmediatePropagation();
51
- const merged = filterParams(href, window.location.search);
52
- const mergedUrl = new URL(merged, window.location.origin);
53
- const fullUrl = `${mergedUrl.pathname}${mergedUrl.search}${mergedUrl.hash}`;
54
- window.history.replaceState({ ...window.history.state }, "", fullUrl);
55
- window.dispatchEvent(
56
- new PopStateEvent("popstate", { state: window.history.state })
57
- );
58
- if (mergedUrl.hash) {
59
- const el = document.querySelector(mergedUrl.hash);
60
- el?.scrollIntoView({ behavior: "smooth" });
21
+ const existingParams = new URLSearchParams(url.search);
22
+ const newParams = new URLSearchParams();
23
+ const addedKeys = /* @__PURE__ */ new Set();
24
+ for (const key of existingParams.keys()) {
25
+ addedKeys.add(decodeURIComponent(key));
61
26
  }
62
- };
63
- document.addEventListener("click", handleSamePageClick, true);
64
- if (window.location.search.length) {
65
- const searchParams = new URLSearchParams(window.location.search);
66
- document.querySelectorAll("a[href]:not(.ext-link)").forEach((anchor) => {
67
- const href = anchor.getAttribute("href")?.trim();
68
- if (href && !href.startsWith("tel:") && !href.startsWith("mailto:") && href !== "#" && href !== "" && !href.startsWith("#")) {
69
- anchor.href = filterParams(href, searchParams.toString());
27
+ for (const [key, value] of searchParams.entries()) {
28
+ const decodedKey = decodeURIComponent(key);
29
+ const decodedValue = decodeURIComponent(value);
30
+ const lowerKey = decodedKey.toLowerCase();
31
+ if (!addedKeys.has(lowerKey) && !decodedKey.includes("[]")) {
32
+ newParams.append(lowerKey, decodedValue);
33
+ addedKeys.add(lowerKey);
34
+ } else if (decodedKey.includes("[]")) {
35
+ const existingValues = existingParams.getAll(key).map(decodeURIComponent);
36
+ if (!existingValues.includes(decodedValue)) {
37
+ newParams.append(decodedKey, decodedValue);
38
+ }
70
39
  }
71
- });
40
+ }
41
+ const mergedParams = new URLSearchParams(existingParams);
42
+ newParams.forEach((value, key) => mergedParams.append(key, value));
43
+ return `${url.origin}${url.pathname}?${mergedParams.toString()}${url.hash}`;
44
+ } catch (e) {
45
+ console.error(e);
46
+ return href;
47
+ }
48
+ };
49
+ const handleAnchorClick = (e, resolved) => {
50
+ if (resolved.includes("#") && !resolved.startsWith("http")) {
51
+ e.preventDefault();
52
+ const hash = resolved.split("#")[1];
53
+ const fullUrl = new URL(resolved, window.location.href);
54
+ window.history.pushState(null, "", fullUrl.search + fullUrl.hash);
55
+ window.dispatchEvent(new PopStateEvent("popstate"));
56
+ document.getElementById(hash)?.scrollIntoView({ behavior: "smooth" });
57
+ return true;
72
58
  }
59
+ return false;
60
+ };
61
+ const appendQueryParams = (currentSearch) => {
62
+ const search = currentSearch ?? window.location.search;
63
+ if (!search.length) return;
64
+ const searchParams = new URLSearchParams(search);
65
+ document.querySelectorAll("a[href]:not(.ext-link)").forEach((anchor) => {
66
+ const href = anchor.getAttribute("href")?.trim();
67
+ if (href && !href.startsWith("tel:") && !href.startsWith("mailto:") && href !== "#" && href !== "" && !href.startsWith("#")) {
68
+ anchor.href = filterParams(href, searchParams.toString());
69
+ }
70
+ });
73
71
  };
74
72
  export {
75
- appendQueryParams
73
+ appendQueryParams,
74
+ filterParams,
75
+ handleAnchorClick
76
76
  };
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { findMoreAxosDomains, getMoreDomains, isAllowedUrl } from "./allowedAxosDomains.js";
3
- import { appendQueryParams } from "./appendQueryParams.js";
3
+ import { appendQueryParams, filterParams, handleAnchorClick } from "./appendQueryParams.js";
4
4
  import { createCachedEmailValidator } from "./emailValidation.js";
5
5
  import { associatedEmail } from "./EverestValidity.js";
6
6
  import { getVariant, getVariantWithRegex } from "./getVariant.js";
@@ -14,10 +14,12 @@ export {
14
14
  columnValues,
15
15
  createCachedEmailValidator,
16
16
  createCachedNMLSValidator,
17
+ filterParams,
17
18
  findMoreAxosDomains,
18
19
  getMoreDomains,
19
20
  getVariant,
20
21
  getVariantWithRegex,
22
+ handleAnchorClick,
21
23
  isAbsoluteUrl,
22
24
  isAllowedUrl,
23
25
  isEmailLink,
@@ -0,0 +1,21 @@
1
+ interface UtagData {
2
+ traffic_type?: string;
3
+ traffic_source?: string;
4
+ [key: string]: unknown;
5
+ }
6
+ declare global {
7
+ interface Window {
8
+ utag?: {
9
+ data: UtagData;
10
+ };
11
+ utag_data?: UtagData;
12
+ }
13
+ }
14
+ export interface OrganicUtms {
15
+ utm_source: string;
16
+ utm_medium: string;
17
+ utm_campaign: string;
18
+ }
19
+ export declare const getTealiumOrganicFallback: () => OrganicUtms | null;
20
+ export declare const hasNoUtms: (params: URLSearchParams) => boolean;
21
+ export {};
@@ -0,0 +1,26 @@
1
+ const getTealiumOrganicFallback = () => {
2
+ if (typeof window === "undefined") return null;
3
+ try {
4
+ const utagData = window.utag?.data ?? window.utag_data ?? {};
5
+ const trafficType = utagData.traffic_type ?? "";
6
+ const trafficSource = utagData.traffic_source ?? "";
7
+ if (trafficType !== "organic" || !trafficSource) return null;
8
+ let sourceName = trafficSource;
9
+ try {
10
+ sourceName = new URL(trafficSource).hostname.replace(/^www\./, "").split(".")[0];
11
+ } catch (_) {
12
+ }
13
+ return {
14
+ utm_source: sourceName,
15
+ utm_medium: "organic",
16
+ utm_campaign: "organic-search"
17
+ };
18
+ } catch {
19
+ return null;
20
+ }
21
+ };
22
+ const hasNoUtms = (params) => !params.has("utm_source") && !params.has("utm_medium") && !params.has("utm_campaign") && !params.has("utm_content") && !params.has("utm_term");
23
+ export {
24
+ getTealiumOrganicFallback,
25
+ hasNoUtms
26
+ };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@axos-web-dev/shared-components",
3
3
  "description": "Axos shared components library for web.",
4
- "version": "2.2.19",
4
+ "version": "2.2.20",
5
5
  "type": "module",
6
6
  "main": "dist/main.js",
7
7
  "module": "dist/main.js",