chore: add custom n-progress component to fix unwanted n-progress trigger issues. (#4965)
* chore: add n-progress lib. * chore: prevent unwanted n-progress from projects and notifications. * fix: lint errors.
This commit is contained in:
parent
209dc57307
commit
626464513d
10 changed files with 463 additions and 12 deletions
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
import { FC, ReactNode } from "react";
|
import { FC, ReactNode } from "react";
|
||||||
import dynamic from "next/dynamic";
|
import dynamic from "next/dynamic";
|
||||||
import { AppProgressBar } from "next-nprogress-bar";
|
|
||||||
import { useTheme, ThemeProvider } from "next-themes";
|
import { useTheme, ThemeProvider } from "next-themes";
|
||||||
import { SWRConfig } from "swr";
|
import { SWRConfig } from "swr";
|
||||||
// ui
|
// ui
|
||||||
|
|
@ -11,6 +10,8 @@ import { Toast } from "@plane/ui";
|
||||||
import { SWR_CONFIG } from "@/constants/swr-config";
|
import { SWR_CONFIG } from "@/constants/swr-config";
|
||||||
//helpers
|
//helpers
|
||||||
import { resolveGeneralTheme } from "@/helpers/theme.helper";
|
import { resolveGeneralTheme } from "@/helpers/theme.helper";
|
||||||
|
// nprogress
|
||||||
|
import { AppProgressBar } from "@/lib/n-progress";
|
||||||
// mobx store provider
|
// mobx store provider
|
||||||
import { StoreProvider } from "@/lib/store-context";
|
import { StoreProvider } from "@/lib/store-context";
|
||||||
// wrappers
|
// wrappers
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,7 @@ export const ProjectCard: React.FC<Props> = observer((props) => {
|
||||||
const handleCopyText = () =>
|
const handleCopyText = () =>
|
||||||
copyUrlToClipboard(projectLink).then(() =>
|
copyUrlToClipboard(projectLink).then(() =>
|
||||||
setToast({
|
setToast({
|
||||||
type: TOAST_TYPE.SUCCESS,
|
type: TOAST_TYPE.INFO,
|
||||||
title: "Link Copied!",
|
title: "Link Copied!",
|
||||||
message: "Project link copied to clipboard.",
|
message: "Project link copied to clipboard.",
|
||||||
})
|
})
|
||||||
|
|
@ -189,6 +189,7 @@ export const ProjectCard: React.FC<Props> = observer((props) => {
|
||||||
if (!isArchived) setJoinProjectModal(true);
|
if (!isArchived) setJoinProjectModal(true);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
data-prevent-nprogress={!project.is_member || isArchived}
|
||||||
className="flex flex-col rounded border border-custom-border-200 bg-custom-background-100"
|
className="flex flex-col rounded border border-custom-border-200 bg-custom-background-100"
|
||||||
>
|
>
|
||||||
<ContextMenu parentRef={projectCardRef} items={MENU_ITEMS} />
|
<ContextMenu parentRef={projectCardRef} items={MENU_ITEMS} />
|
||||||
|
|
@ -220,7 +221,7 @@ export const ProjectCard: React.FC<Props> = observer((props) => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{!isArchived && (
|
{!isArchived && (
|
||||||
<div className="flex h-full flex-shrink-0 items-center gap-2">
|
<div data-prevent-nprogress className="flex h-full flex-shrink-0 items-center gap-2">
|
||||||
<button
|
<button
|
||||||
className="flex h-6 w-6 items-center justify-center rounded bg-white/10"
|
className="flex h-6 w-6 items-center justify-center rounded bg-white/10"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// type
|
// type
|
||||||
import { AppRouterInstance } from "next/dist/shared/lib/app-router-context.shared-runtime";
|
import { AppRouterInstance } from "next/dist/shared/lib/app-router-context.shared-runtime";
|
||||||
// router from next-nprogress-bar
|
// router from next-nprogress-bar
|
||||||
import { useRouter } from "next-nprogress-bar";
|
import { useRouter } from "@/lib/n-progress";
|
||||||
|
|
||||||
export const useAppRouter = (): AppRouterInstance => useRouter();
|
export const useAppRouter = (): AppRouterInstance => useRouter();
|
||||||
|
|
|
||||||
303
web/core/lib/n-progress/AppProgressBar.tsx
Normal file
303
web/core/lib/n-progress/AppProgressBar.tsx
Normal file
|
|
@ -0,0 +1,303 @@
|
||||||
|
import React, { useCallback, useEffect, useMemo, useRef } from "react";
|
||||||
|
import { NavigateOptions } from "next/dist/shared/lib/app-router-context.shared-runtime";
|
||||||
|
import { usePathname, useSearchParams, useRouter as useNextRouter } from "next/navigation";
|
||||||
|
import NProgress from "nprogress";
|
||||||
|
import { getAnchorProperty, hasPreventProgressAttribute } from "./utils/getAnchorProperty";
|
||||||
|
import { isSameURL, isSameURLWithoutSearch } from "./utils/sameURL";
|
||||||
|
import { ProgressBarProps, RouterNProgressOptions } from ".";
|
||||||
|
|
||||||
|
type PushStateInput = [data: any, unused: string, url?: string | URL | null | undefined];
|
||||||
|
|
||||||
|
export const AppProgressBar = React.memo(
|
||||||
|
({
|
||||||
|
color = "#0A2FFF",
|
||||||
|
height = "2px",
|
||||||
|
options,
|
||||||
|
shallowRouting = false,
|
||||||
|
disableSameURL = true,
|
||||||
|
startPosition = 0,
|
||||||
|
delay = 0,
|
||||||
|
stopDelay = 0,
|
||||||
|
style,
|
||||||
|
nonce,
|
||||||
|
targetPreprocessor,
|
||||||
|
disableAnchorClick = false,
|
||||||
|
}: ProgressBarProps) => {
|
||||||
|
const styles = (
|
||||||
|
<style nonce={nonce}>
|
||||||
|
{style ||
|
||||||
|
`
|
||||||
|
#nprogress {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#nprogress .bar {
|
||||||
|
background: ${color};
|
||||||
|
|
||||||
|
position: fixed;
|
||||||
|
z-index: 1031;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
height: ${height};
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fancy blur effect */
|
||||||
|
#nprogress .peg {
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
right: 0px;
|
||||||
|
width: 100px;
|
||||||
|
height: 100%;
|
||||||
|
box-shadow: 0 0 10px ${color}, 0 0 5px ${color};
|
||||||
|
opacity: 1.0;
|
||||||
|
|
||||||
|
-webkit-transform: rotate(3deg) translate(0px, -4px);
|
||||||
|
-ms-transform: rotate(3deg) translate(0px, -4px);
|
||||||
|
transform: rotate(3deg) translate(0px, -4px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove these to get rid of the spinner */
|
||||||
|
#nprogress .spinner {
|
||||||
|
display: block;
|
||||||
|
position: fixed;
|
||||||
|
z-index: 1031;
|
||||||
|
top: 15px;
|
||||||
|
right: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#nprogress .spinner-icon {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
border: solid 2px transparent;
|
||||||
|
border-top-color: ${color};
|
||||||
|
border-left-color: ${color};
|
||||||
|
border-radius: 50%;
|
||||||
|
|
||||||
|
-webkit-animation: nprogress-spinner 400ms linear infinite;
|
||||||
|
animation: nprogress-spinner 400ms linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nprogress-custom-parent {
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nprogress-custom-parent #nprogress .spinner,
|
||||||
|
.nprogress-custom-parent #nprogress .bar {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes nprogress-spinner {
|
||||||
|
0% { -webkit-transform: rotate(0deg); }
|
||||||
|
100% { -webkit-transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
@keyframes nprogress-spinner {
|
||||||
|
0% { transform: rotate(0deg); }
|
||||||
|
100% { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
</style>
|
||||||
|
);
|
||||||
|
|
||||||
|
NProgress.configure(options || {});
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
let progressDoneTimer: NodeJS.Timeout;
|
||||||
|
|
||||||
|
const pathname = usePathname();
|
||||||
|
const searchParams = useSearchParams();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (progressDoneTimer) clearTimeout(progressDoneTimer);
|
||||||
|
progressDoneTimer = setTimeout(() => {
|
||||||
|
NProgress.done();
|
||||||
|
}, stopDelay);
|
||||||
|
}, [pathname, searchParams]);
|
||||||
|
|
||||||
|
const elementsWithAttachedHandlers = useRef<(HTMLAnchorElement | SVGAElement)[]>([]);
|
||||||
|
useEffect(() => {
|
||||||
|
if (disableAnchorClick) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
let timer: NodeJS.Timeout;
|
||||||
|
|
||||||
|
const startProgress = () => {
|
||||||
|
timer = setTimeout(() => {
|
||||||
|
if (startPosition > 0) NProgress.set(startPosition);
|
||||||
|
NProgress.start();
|
||||||
|
}, delay);
|
||||||
|
};
|
||||||
|
|
||||||
|
const stopProgress = () => {
|
||||||
|
if (timer) clearTimeout(timer);
|
||||||
|
timer = setTimeout(() => {
|
||||||
|
NProgress.done();
|
||||||
|
}, stopDelay);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleAnchorClick: any = (event: MouseEvent) => {
|
||||||
|
// Skip preventDefault
|
||||||
|
if (event.defaultPrevented) return;
|
||||||
|
|
||||||
|
const anchorElement = event.currentTarget as HTMLAnchorElement | SVGAElement;
|
||||||
|
const target = event.target as HTMLElement | Element;
|
||||||
|
// Check if the target or any of its parents have the attribute
|
||||||
|
const preventProgress =
|
||||||
|
hasPreventProgressAttribute(target) || anchorElement?.getAttribute("data-prevent-nprogress") === "true";
|
||||||
|
|
||||||
|
if (preventProgress) return;
|
||||||
|
|
||||||
|
const anchorTarget = getAnchorProperty(anchorElement, "target");
|
||||||
|
// Skip anchors with target="_blank"
|
||||||
|
if (anchorTarget === "_blank") return;
|
||||||
|
|
||||||
|
// Skip control/command/option/alt+click
|
||||||
|
if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
|
||||||
|
|
||||||
|
const targetHref = getAnchorProperty(anchorElement, "href");
|
||||||
|
const targetUrl = targetPreprocessor ? targetPreprocessor(new URL(targetHref)) : new URL(targetHref);
|
||||||
|
const currentUrl = new URL(location.href);
|
||||||
|
|
||||||
|
if (shallowRouting && isSameURLWithoutSearch(targetUrl, currentUrl) && disableSameURL) return;
|
||||||
|
if (isSameURL(targetUrl, currentUrl) && disableSameURL) return;
|
||||||
|
|
||||||
|
startProgress();
|
||||||
|
};
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
const handleMutation: MutationCallback = () => {
|
||||||
|
const anchorElements = Array.from(document.querySelectorAll("a")) as (HTMLAnchorElement | SVGAElement)[];
|
||||||
|
|
||||||
|
const validAnchorElements = anchorElements.filter((anchor) => {
|
||||||
|
const href = getAnchorProperty(anchor, "href");
|
||||||
|
const isNProgressDisabled = anchor.getAttribute("data-disable-nprogress") === "true";
|
||||||
|
const isNotTelOrMailto =
|
||||||
|
href &&
|
||||||
|
!href.startsWith("tel:") &&
|
||||||
|
!href.startsWith("mailto:") &&
|
||||||
|
!href.startsWith("blob:") &&
|
||||||
|
!href.startsWith("javascript:");
|
||||||
|
|
||||||
|
return !isNProgressDisabled && isNotTelOrMailto && getAnchorProperty(anchor, "target") !== "_blank";
|
||||||
|
});
|
||||||
|
|
||||||
|
validAnchorElements.forEach((anchor) => anchor.addEventListener("click", handleAnchorClick));
|
||||||
|
elementsWithAttachedHandlers.current = validAnchorElements;
|
||||||
|
};
|
||||||
|
|
||||||
|
const mutationObserver = new MutationObserver(handleMutation);
|
||||||
|
mutationObserver.observe(document, { childList: true, subtree: true });
|
||||||
|
|
||||||
|
const originalWindowHistoryPushState = window.history.pushState;
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
window.history.pushState = new Proxy(window.history.pushState, {
|
||||||
|
apply: (target, thisArg, argArray: PushStateInput) => {
|
||||||
|
stopProgress();
|
||||||
|
return target.apply(thisArg, argArray);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
mutationObserver.disconnect();
|
||||||
|
elementsWithAttachedHandlers.current.forEach((anchor) => {
|
||||||
|
anchor.removeEventListener("click", handleAnchorClick);
|
||||||
|
});
|
||||||
|
elementsWithAttachedHandlers.current = [];
|
||||||
|
window.history.pushState = originalWindowHistoryPushState;
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return styles;
|
||||||
|
},
|
||||||
|
(prevProps, nextProps) => {
|
||||||
|
if (nextProps?.memo === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!nextProps?.shouldCompareComplexProps) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
prevProps?.color === nextProps?.color &&
|
||||||
|
prevProps?.height === nextProps?.height &&
|
||||||
|
prevProps?.shallowRouting === nextProps?.shallowRouting &&
|
||||||
|
prevProps?.startPosition === nextProps?.startPosition &&
|
||||||
|
prevProps?.delay === nextProps?.delay &&
|
||||||
|
prevProps?.disableSameURL === nextProps?.disableSameURL &&
|
||||||
|
prevProps?.stopDelay === nextProps?.stopDelay &&
|
||||||
|
prevProps?.nonce === nextProps?.nonce &&
|
||||||
|
JSON.stringify(prevProps?.options) === JSON.stringify(nextProps?.options) &&
|
||||||
|
prevProps?.style === nextProps?.style &&
|
||||||
|
prevProps.disableAnchorClick === nextProps.disableAnchorClick
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
AppProgressBar.displayName = "AppProgressBar";
|
||||||
|
|
||||||
|
export function useRouter() {
|
||||||
|
const router = useNextRouter();
|
||||||
|
|
||||||
|
const startProgress = useCallback(
|
||||||
|
(startPosition?: number) => {
|
||||||
|
if (startPosition && startPosition > 0) NProgress.set(startPosition);
|
||||||
|
NProgress.start();
|
||||||
|
},
|
||||||
|
[router]
|
||||||
|
);
|
||||||
|
|
||||||
|
const progress = useCallback(
|
||||||
|
(href: string, options?: NavigateOptions, NProgressOptions?: RouterNProgressOptions) => {
|
||||||
|
if (NProgressOptions?.showProgressBar === false) {
|
||||||
|
return router.push(href, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentUrl = new URL(location.href);
|
||||||
|
const targetUrl = new URL(href, location.href);
|
||||||
|
|
||||||
|
if (isSameURL(targetUrl, currentUrl) && NProgressOptions?.disableSameURL !== false)
|
||||||
|
return router.push(href, options);
|
||||||
|
|
||||||
|
startProgress(NProgressOptions?.startPosition);
|
||||||
|
},
|
||||||
|
[router]
|
||||||
|
);
|
||||||
|
|
||||||
|
const push = useCallback(
|
||||||
|
(href: string, options?: NavigateOptions, NProgressOptions?: RouterNProgressOptions) => {
|
||||||
|
progress(href, options, NProgressOptions);
|
||||||
|
return router.push(href, options);
|
||||||
|
},
|
||||||
|
[router, startProgress]
|
||||||
|
);
|
||||||
|
|
||||||
|
const replace = useCallback(
|
||||||
|
(href: string, options?: NavigateOptions, NProgressOptions?: RouterNProgressOptions) => {
|
||||||
|
progress(href, options, NProgressOptions);
|
||||||
|
return router.replace(href, options);
|
||||||
|
},
|
||||||
|
[router, startProgress]
|
||||||
|
);
|
||||||
|
|
||||||
|
const back = useCallback(
|
||||||
|
(NProgressOptions?: RouterNProgressOptions) => {
|
||||||
|
if (NProgressOptions?.showProgressBar === false) return router.back();
|
||||||
|
|
||||||
|
startProgress(NProgressOptions?.startPosition);
|
||||||
|
|
||||||
|
return router.back();
|
||||||
|
},
|
||||||
|
[router]
|
||||||
|
);
|
||||||
|
|
||||||
|
const enhancedRouter = useMemo(() => ({ ...router, push, replace, back }), [router, push, replace, back]);
|
||||||
|
|
||||||
|
return enhancedRouter;
|
||||||
|
}
|
||||||
68
web/core/lib/n-progress/index.tsx
Normal file
68
web/core/lib/n-progress/index.tsx
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
import { start, done } from 'nprogress';
|
||||||
|
import {
|
||||||
|
AppProgressBar as AppProgressBarComponent,
|
||||||
|
useRouter,
|
||||||
|
} from './AppProgressBar';
|
||||||
|
import withSuspense from './withSuspense';
|
||||||
|
|
||||||
|
export interface NProgressOptions {
|
||||||
|
minimum?: number;
|
||||||
|
template?: string;
|
||||||
|
easing?: string;
|
||||||
|
speed?: number;
|
||||||
|
trickle?: boolean;
|
||||||
|
trickleSpeed?: number;
|
||||||
|
showSpinner?: boolean;
|
||||||
|
parent?: string;
|
||||||
|
positionUsing?: string;
|
||||||
|
barSelector?: string;
|
||||||
|
spinnerSelector?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param color Color of the progress bar. @default #0A2FFF
|
||||||
|
* @param height Height of the progress bar. @default 2px
|
||||||
|
* @param options NProgress options. @default undefined
|
||||||
|
* @param shallowRouting If the progress bar is not displayed when you use shallow routing - @default false
|
||||||
|
* @param startPosition The position of the progress bar at the start of the page load - @default 0
|
||||||
|
* @param delay When the page loads faster than the progress bar, it does not display - @default 0
|
||||||
|
* @param stopDelay Delay to stop the progress bar - @default 0
|
||||||
|
* @param style Custom css - @default undefined
|
||||||
|
* @param nonce Custom nonce for Content-Security-Policy directives - @default undefined
|
||||||
|
* @param shouldCompareComplexProps If you want to compare props in the React.memo return - @default false
|
||||||
|
* @param targetPreprocessor If you want to./AppProgressBaress the target URL - @default undefined
|
||||||
|
* @param disableAnchorClick Disable triggering progress bar on anchor clicks - @default false
|
||||||
|
*/
|
||||||
|
export interface ProgressBarProps {
|
||||||
|
color?: string;
|
||||||
|
height?: string;
|
||||||
|
options?: Partial<NProgressOptions>;
|
||||||
|
shallowRouting?: boolean;
|
||||||
|
disableSameURL?: boolean;
|
||||||
|
startPosition?: number;
|
||||||
|
delay?: number;
|
||||||
|
stopDelay?: number;
|
||||||
|
style?: string;
|
||||||
|
nonce?: string;
|
||||||
|
memo?: boolean;
|
||||||
|
shouldCompareComplexProps?: boolean;
|
||||||
|
targetPreprocessor?: (url: URL) => URL;
|
||||||
|
disableAnchorClick?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RouterNProgressOptions {
|
||||||
|
showProgressBar?: boolean;
|
||||||
|
startPosition?: number;
|
||||||
|
disableSameURL?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const startProgress = () => {
|
||||||
|
start();
|
||||||
|
};
|
||||||
|
|
||||||
|
export const stopProgress = (force?: boolean) => {
|
||||||
|
done(force);
|
||||||
|
};
|
||||||
|
|
||||||
|
const AppProgressBar = withSuspense<ProgressBarProps>(AppProgressBarComponent);
|
||||||
|
export { AppProgressBar, useRouter };
|
||||||
59
web/core/lib/n-progress/utils/getAnchorProperty.ts
Normal file
59
web/core/lib/n-progress/utils/getAnchorProperty.ts
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
function parsePath(path: string) {
|
||||||
|
const hashIndex = path.indexOf("#");
|
||||||
|
const queryIndex = path.indexOf("?");
|
||||||
|
const hasQuery = queryIndex > -1 && (hashIndex < 0 || queryIndex < hashIndex);
|
||||||
|
|
||||||
|
if (hasQuery || hashIndex > -1) {
|
||||||
|
return {
|
||||||
|
pathname: path.substring(0, hasQuery ? queryIndex : hashIndex),
|
||||||
|
query: hasQuery ? path.substring(queryIndex, hashIndex > -1 ? hashIndex : undefined) : "",
|
||||||
|
hash: hashIndex > -1 ? path.slice(hashIndex) : "",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return { pathname: path, query: "", hash: "" };
|
||||||
|
}
|
||||||
|
|
||||||
|
function addPathPrefix(path: string, prefix?: string) {
|
||||||
|
if (!path.startsWith("/") || !prefix) {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { pathname, query, hash } = parsePath(path);
|
||||||
|
return `${prefix}${pathname}${query}${hash}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getAnchorProperty<T extends HTMLAnchorElement | SVGAElement, K extends keyof T, P extends T[K]>(
|
||||||
|
a: T,
|
||||||
|
key: K
|
||||||
|
): P extends SVGAnimatedString ? string : P {
|
||||||
|
if (typeof key === "string" && key === "data-disable-nprogress") {
|
||||||
|
const dataKey = key.substring(5) as keyof DOMStringMap;
|
||||||
|
return a.dataset[dataKey] as any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const prop = a[key];
|
||||||
|
|
||||||
|
if (prop instanceof SVGAnimatedString) {
|
||||||
|
const value = prop.baseVal as unknown;
|
||||||
|
|
||||||
|
if (key === "href") {
|
||||||
|
return addPathPrefix(value as string, location.origin) as any;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value as any;
|
||||||
|
}
|
||||||
|
|
||||||
|
return prop as any;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Utility function to check for attribute in parent elements
|
||||||
|
export const hasPreventProgressAttribute = (element: Element | null): boolean => {
|
||||||
|
while (element) {
|
||||||
|
if (element?.getAttribute("data-prevent-nprogress") === "true") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
element = element?.parentElement;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
16
web/core/lib/n-progress/utils/sameURL.ts
Normal file
16
web/core/lib/n-progress/utils/sameURL.ts
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
export function isSameURL(target: URL, current: URL) {
|
||||||
|
const cleanTarget =
|
||||||
|
target.protocol + '//' + target.host + target.pathname + target.search;
|
||||||
|
const cleanCurrent =
|
||||||
|
current.protocol + '//' + current.host + current.pathname + current.search;
|
||||||
|
|
||||||
|
return cleanTarget === cleanCurrent;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isSameURLWithoutSearch(target: URL, current: URL) {
|
||||||
|
const cleanTarget = target.protocol + '//' + target.host + target.pathname;
|
||||||
|
const cleanCurrent =
|
||||||
|
current.protocol + '//' + current.host + current.pathname;
|
||||||
|
|
||||||
|
return cleanTarget === cleanCurrent;
|
||||||
|
}
|
||||||
11
web/core/lib/n-progress/withSuspense.tsx
Normal file
11
web/core/lib/n-progress/withSuspense.tsx
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
import React, { ComponentType, Suspense } from "react";
|
||||||
|
|
||||||
|
export default function withSuspense<P extends object>(Component: ComponentType<P>) {
|
||||||
|
return function WithSuspenseComponent(props: P) {
|
||||||
|
return (
|
||||||
|
<Suspense>
|
||||||
|
<Component {...props} />
|
||||||
|
</Suspense>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -42,7 +42,6 @@
|
||||||
"mobx-react": "^9.1.1",
|
"mobx-react": "^9.1.1",
|
||||||
"mobx-utils": "^6.0.8",
|
"mobx-utils": "^6.0.8",
|
||||||
"next": "^14.2.3",
|
"next": "^14.2.3",
|
||||||
"next-nprogress-bar": "^2.3.12",
|
|
||||||
"next-pwa": "^5.6.0",
|
"next-pwa": "^5.6.0",
|
||||||
"next-themes": "^0.2.1",
|
"next-themes": "^0.2.1",
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
|
|
|
||||||
|
|
@ -9948,13 +9948,6 @@ neo-async@^2.5.0, neo-async@^2.6.2:
|
||||||
resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
|
resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
|
||||||
integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==
|
integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==
|
||||||
|
|
||||||
next-nprogress-bar@^2.3.12:
|
|
||||||
version "2.3.12"
|
|
||||||
resolved "https://registry.yarnpkg.com/next-nprogress-bar/-/next-nprogress-bar-2.3.12.tgz#ecc8426946d7635cfb60e22b2dc71d8b6d91a6b4"
|
|
||||||
integrity sha512-BCsmNmssPY4QfYKux7cGYm/JmsM/n9TGMJJDyYPt7ckWyK8l43hMgi7g9d7u/IxCaEAx3pbzfg7Ity0zdlDnGA==
|
|
||||||
dependencies:
|
|
||||||
nprogress "^0.2.0"
|
|
||||||
|
|
||||||
next-pwa@^5.6.0:
|
next-pwa@^5.6.0:
|
||||||
version "5.6.0"
|
version "5.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/next-pwa/-/next-pwa-5.6.0.tgz#f7b1960c4fdd7be4253eb9b41b612ac773392bf4"
|
resolved "https://registry.yarnpkg.com/next-pwa/-/next-pwa-5.6.0.tgz#f7b1960c4fdd7be4253eb9b41b612ac773392bf4"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue