@axos-web-dev/shared-components 2.0.0-queryparams.1 → 2.0.0-queryparams.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.
@@ -13,6 +13,7 @@ import '../assets/Modal/Modal.css';import '../assets/VideoWrapper/VideoWrapper.c
13
13
  /* empty css */
14
14
  /* empty css */
15
15
  import { getVariant } from "../utils/getVariant.js";
16
+ import { isInternalSamePathHref, mergeHrefWithCurrentSearch, performSamePageQueryParamNavigation } from "../utils/samePageQueryParamsNavigation.js";
16
17
  import clsx from "clsx";
17
18
  import { useState, createElement } from "react";
18
19
  import "../AlertBanner/AlertBanner.css.js";
@@ -160,6 +161,17 @@ const Button = ({
160
161
  handleSamePageNavigation(e);
161
162
  return;
162
163
  }
164
+ const resolvedHref = resolveUrl(targetUrl);
165
+ if (e.currentTarget instanceof HTMLAnchorElement && !e.currentTarget.classList.contains("ext-link") && isInternalSamePathHref(resolvedHref)) {
166
+ e.preventDefault();
167
+ e.nativeEvent.stopImmediatePropagation();
168
+ const merged = mergeHrefWithCurrentSearch(
169
+ resolvedHref,
170
+ window.location.search
171
+ );
172
+ performSamePageQueryParamNavigation(merged);
173
+ return;
174
+ }
163
175
  const external_link = validateLink(targetUrl);
164
176
  if (external_link) {
165
177
  e.preventDefault();
@@ -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 { isInternalSamePathHref, mergeHrefWithCurrentSearch, performSamePageQueryParamNavigation } from "../utils/samePageQueryParamsNavigation.js";
21
22
  import clsx from "clsx";
22
23
  import "../Button/Button.css.js";
23
24
  import "react-use";
@@ -172,6 +173,17 @@ const Chevron = ({
172
173
  };
173
174
  const onClick = !goBack ? (e) => {
174
175
  if (targetUrl) {
176
+ const resolvedHref = resolveUrl(targetUrl);
177
+ if (e.currentTarget instanceof HTMLAnchorElement && !e.currentTarget.classList.contains("ext-link") && isInternalSamePathHref(resolvedHref)) {
178
+ e.preventDefault();
179
+ e.nativeEvent.stopImmediatePropagation();
180
+ const merged = mergeHrefWithCurrentSearch(
181
+ resolvedHref,
182
+ window.location.search
183
+ );
184
+ performSamePageQueryParamNavigation(merged);
185
+ return;
186
+ }
175
187
  const external_link = validateLink(targetUrl);
176
188
  if (external_link) {
177
189
  e.nativeEvent.stopImmediatePropagation();
@@ -11,6 +11,7 @@ import '../assets/Modal/Modal.css';import '../assets/VideoWrapper/VideoWrapper.c
11
11
  /* empty css */
12
12
  /* empty css */
13
13
  /* empty css */
14
+ import { isInternalSamePathHref, mergeHrefWithCurrentSearch, performSamePageQueryParamNavigation } from "../utils/samePageQueryParamsNavigation.js";
14
15
  import clsx from "clsx";
15
16
  import "react";
16
17
  import "../AlertBanner/AlertBanner.css.js";
@@ -142,6 +143,17 @@ const Hyperlink = ({
142
143
  const isTelOrMailto = targetUrl && (isPhoneLink(targetUrl) || isEmailLink(targetUrl));
143
144
  const onClick = (e) => {
144
145
  if (targetUrl) {
146
+ const resolvedHref = resolveUrl(targetUrl);
147
+ if (e.currentTarget instanceof HTMLAnchorElement && !e.currentTarget.classList.contains("ext-link") && isInternalSamePathHref(resolvedHref)) {
148
+ e.preventDefault();
149
+ e.nativeEvent.stopImmediatePropagation();
150
+ const merged = mergeHrefWithCurrentSearch(
151
+ resolvedHref,
152
+ window.location.search
153
+ );
154
+ performSamePageQueryParamNavigation(merged);
155
+ return;
156
+ }
145
157
  const external_link = validateLink(targetUrl);
146
158
  if (external_link) {
147
159
  e.nativeEvent.stopImmediatePropagation();
package/dist/main.js CHANGED
@@ -209,6 +209,7 @@ import { Tab } from "./Tab/Tab.js";
209
209
  import { TabContainer } from "./Tab/TabContainer.js";
210
210
  import { findMoreAxosDomains, getMoreDomains, isAllowedUrl } from "./utils/allowedAxosDomains.js";
211
211
  import { appendQueryParams } from "./utils/appendQueryParams.js";
212
+ import { isInternalSamePathHref, isSkippableAnchorHref, mergeHrefWithCurrentSearch, performSamePageQueryParamNavigation } from "./utils/samePageQueryParamsNavigation.js";
212
213
  import { createCachedEmailValidator } from "./utils/emailValidation.js";
213
214
  import { associatedEmail } from "./utils/EverestValidity.js";
214
215
  import { getVariant, getVariantWithRegex } from "./utils/getVariant.js";
@@ -676,7 +677,9 @@ export {
676
677
  isAbsoluteUrl,
677
678
  isAllowedUrl,
678
679
  isEmailLink,
680
+ isInternalSamePathHref,
679
681
  isPhoneLink,
682
+ isSkippableAnchorHref,
680
683
  isValidHoneyPot,
681
684
  is_bg_img,
682
685
  isolate_container,
@@ -702,6 +705,7 @@ export {
702
705
  mb_8,
703
706
  mb_form,
704
707
  media,
708
+ mergeHrefWithCurrentSearch,
705
709
  messageStyle,
706
710
  messagesContainerStyle,
707
711
  mh_330,
@@ -723,6 +727,7 @@ export {
723
727
  padding,
724
728
  padding_in_footer,
725
729
  paragraph,
730
+ performSamePageQueryParamNavigation,
726
731
  person,
727
732
  picker_arrow,
728
733
  picker_container,
@@ -1,72 +1,35 @@
1
+ import { isSkippableAnchorHref, mergeHrefWithCurrentSearch, performSamePageQueryParamNavigation } from "./samePageQueryParamsNavigation.js";
2
+ let samePageQueryClickListenerAttached = false;
1
3
  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
- }
16
- 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
- }
28
- }
29
- }
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;
36
- }
37
- };
4
+ if (typeof window === "undefined") return;
38
5
  const handleSamePageClick = (e) => {
39
6
  const anchor = e.target?.closest?.("a[href]");
40
7
  if (!anchor || anchor.classList.contains("ext-link"))
41
8
  return;
42
9
  const href = anchor.getAttribute("href")?.trim();
43
- if (!href || href.startsWith("tel:") || href.startsWith("mailto:") || href === "#" || href === "" || href.startsWith("#"))
44
- return;
10
+ if (isSkippableAnchorHref(href)) return;
45
11
  const base = window.location.origin + window.location.pathname + window.location.search;
46
12
  const url = new URL(href, base);
47
- if (url.origin !== currentOrigin || url.pathname !== currentPathname)
13
+ if (url.origin !== window.location.origin || url.pathname !== window.location.pathname)
48
14
  return;
49
15
  e.preventDefault();
50
16
  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" });
61
- }
17
+ const merged = mergeHrefWithCurrentSearch(href, window.location.search);
18
+ performSamePageQueryParamNavigation(merged);
62
19
  };
63
- document.addEventListener("click", handleSamePageClick, true);
20
+ if (!samePageQueryClickListenerAttached) {
21
+ samePageQueryClickListenerAttached = true;
22
+ window.addEventListener("click", handleSamePageClick, true);
23
+ }
64
24
  if (window.location.search.length) {
65
25
  const searchParams = new URLSearchParams(window.location.search);
66
26
  document.querySelectorAll("a[href]:not(.ext-link)").forEach((anchor) => {
67
27
  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());
28
+ if (!isSkippableAnchorHref(href)) {
29
+ anchor.href = mergeHrefWithCurrentSearch(
30
+ href,
31
+ searchParams.toString()
32
+ );
70
33
  }
71
34
  });
72
35
  }
@@ -1,5 +1,6 @@
1
1
  export * from './allowedAxosDomains';
2
2
  export * from './appendQueryParams';
3
+ export * from './samePageQueryParamsNavigation';
3
4
  export * from './emailValidation';
4
5
  export * from './EverestValidity';
5
6
  export * from './getVariant';
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { findMoreAxosDomains, getMoreDomains, isAllowedUrl } from "./allowedAxosDomains.js";
3
3
  import { appendQueryParams } from "./appendQueryParams.js";
4
+ import { isInternalSamePathHref, isSkippableAnchorHref, mergeHrefWithCurrentSearch, performSamePageQueryParamNavigation } from "./samePageQueryParamsNavigation.js";
4
5
  import { createCachedEmailValidator } from "./emailValidation.js";
5
6
  import { associatedEmail } from "./EverestValidity.js";
6
7
  import { getVariant, getVariantWithRegex } from "./getVariant.js";
@@ -21,7 +22,11 @@ export {
21
22
  isAbsoluteUrl,
22
23
  isAllowedUrl,
23
24
  isEmailLink,
25
+ isInternalSamePathHref,
24
26
  isPhoneLink,
27
+ isSkippableAnchorHref,
28
+ mergeHrefWithCurrentSearch,
29
+ performSamePageQueryParamNavigation,
25
30
  shortUrl,
26
31
  useCachedEmailValidator,
27
32
  useCachedNMLSValidator,
@@ -0,0 +1,4 @@
1
+ export declare function mergeHrefWithCurrentSearch(href: string, currentSearch?: string): string;
2
+ export declare function isSkippableAnchorHref(href: string | undefined | null): boolean;
3
+ export declare function isInternalSamePathHref(href: string): boolean;
4
+ export declare function performSamePageQueryParamNavigation(mergedHref: string): void;
@@ -0,0 +1,63 @@
1
+ function mergeHrefWithCurrentSearch(href, currentSearch) {
2
+ try {
3
+ const search = currentSearch ?? window.location.search;
4
+ const searchParams = new URLSearchParams(search);
5
+ const base = window.location.origin + window.location.pathname + window.location.search;
6
+ const url = new URL(href.trim(), base);
7
+ const existingParams = new URLSearchParams(url.search);
8
+ const newParams = new URLSearchParams();
9
+ const addedKeys = /* @__PURE__ */ new Set();
10
+ for (const key of existingParams.keys()) {
11
+ addedKeys.add(decodeURIComponent(key));
12
+ }
13
+ for (const [key, value] of searchParams.entries()) {
14
+ const decodedKey = decodeURIComponent(key);
15
+ const decodedValue = decodeURIComponent(value);
16
+ const lowerKey = decodedKey.toLowerCase();
17
+ if (!addedKeys.has(lowerKey) && !decodedKey.includes("[]")) {
18
+ newParams.append(lowerKey, decodedValue);
19
+ addedKeys.add(lowerKey);
20
+ } else if (decodedKey.includes("[]")) {
21
+ const existingValues = existingParams.getAll(key).map(decodeURIComponent);
22
+ if (!existingValues.includes(decodedValue)) {
23
+ newParams.append(decodedKey, decodedValue);
24
+ }
25
+ }
26
+ }
27
+ const mergedParams = new URLSearchParams(existingParams);
28
+ newParams.forEach((value, key) => mergedParams.append(key, value));
29
+ return `${url.origin}${url.pathname}?${mergedParams.toString()}${url.hash}`;
30
+ } catch (e) {
31
+ console.error(e);
32
+ return href;
33
+ }
34
+ }
35
+ function isSkippableAnchorHref(href) {
36
+ if (!href) return true;
37
+ const h = href.trim();
38
+ return !h || h.startsWith("tel:") || h.startsWith("mailto:") || h === "#" || h === "" || h.startsWith("#");
39
+ }
40
+ function isInternalSamePathHref(href) {
41
+ if (isSkippableAnchorHref(href)) return false;
42
+ const base = window.location.origin + window.location.pathname + window.location.search;
43
+ const url = new URL(href.trim(), base);
44
+ return url.origin === window.location.origin && url.pathname === window.location.pathname;
45
+ }
46
+ function performSamePageQueryParamNavigation(mergedHref) {
47
+ const mergedUrl = new URL(mergedHref, window.location.origin);
48
+ const fullUrl = `${mergedUrl.pathname}${mergedUrl.search}${mergedUrl.hash}`;
49
+ window.history.replaceState({ ...window.history.state }, "", fullUrl);
50
+ window.dispatchEvent(
51
+ new PopStateEvent("popstate", { state: window.history.state })
52
+ );
53
+ if (mergedUrl.hash) {
54
+ const el = document.querySelector(mergedUrl.hash);
55
+ el?.scrollIntoView({ behavior: "smooth" });
56
+ }
57
+ }
58
+ export {
59
+ isInternalSamePathHref,
60
+ isSkippableAnchorHref,
61
+ mergeHrefWithCurrentSearch,
62
+ performSamePageQueryParamNavigation
63
+ };
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.0.0-queryparams.1",
4
+ "version": "2.0.0-queryparams.2",
5
5
  "type": "module",
6
6
  "main": "index.js",
7
7
  "module": "dist/main.js",