diff --git a/README.md b/README.md
index db82723..555a4f1 100644
--- a/README.md
+++ b/README.md
@@ -135,3 +135,4 @@ onClick={(e) => {
| `showSpinner` | `boolean` | Determines whether to accompany the loading bar with a spinner. Turned off by default. | `false` |
| `ignoreSearchParams` | `boolean` | Determines whether to ignore search parameters in the URL when triggering the loader. Turned off by default. | `false` |
| `dir` | `ltr` or `rtl` | Sets the direction of the top-loading bar. | `ltr` |
+| `delay` | `number` | Specifies the delay in milliseconds before starting the progress bar. | `0` |
diff --git a/src/__tests__/HolyLoader.test.ts b/src/__tests__/HolyLoader.test.ts
new file mode 100644
index 0000000..1fde3f9
--- /dev/null
+++ b/src/__tests__/HolyLoader.test.ts
@@ -0,0 +1,58 @@
+import { describe, expect, it, vi } from 'vitest';
+import { render, fireEvent } from '@testing-library/react';
+import HolyLoader, { startHolyLoader, stopHolyLoader } from '../index';
+
+describe('HolyLoader', () => {
+ it('should start the progress bar after the specified delay', () => {
+ vi.useFakeTimers();
+ const { container } = render();
+ const anchor = document.createElement('a');
+ anchor.href = '/test';
+ document.body.appendChild(anchor);
+
+ fireEvent.click(anchor);
+ expect(container.querySelector('#holy-progress')).toBeNull();
+
+ vi.advanceTimersByTime(200);
+ expect(container.querySelector('#holy-progress')).not.toBeNull();
+
+ vi.useRealTimers();
+ });
+
+ it('should not start the progress bar if navigation happens within the delay', () => {
+ vi.useFakeTimers();
+ const { container } = render();
+ const anchor = document.createElement('a');
+ anchor.href = '/test';
+ document.body.appendChild(anchor);
+
+ fireEvent.click(anchor);
+ expect(container.querySelector('#holy-progress')).toBeNull();
+
+ fireEvent.click(anchor);
+ vi.advanceTimersByTime(200);
+ expect(container.querySelector('#holy-progress')).toBeNull();
+
+ vi.useRealTimers();
+ });
+
+ it('should start the progress bar immediately if delay is 0', () => {
+ const { container } = render();
+ const anchor = document.createElement('a');
+ anchor.href = '/test';
+ document.body.appendChild(anchor);
+
+ fireEvent.click(anchor);
+ expect(container.querySelector('#holy-progress')).not.toBeNull();
+ });
+
+ it('should manually start and stop the progress bar', () => {
+ const { container } = render();
+
+ startHolyLoader();
+ expect(container.querySelector('#holy-progress')).not.toBeNull();
+
+ stopHolyLoader();
+ expect(container.querySelector('#holy-progress')).toBeNull();
+ });
+});
diff --git a/src/index.tsx b/src/index.tsx
index 8d23653..2d2bd4b 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -72,6 +72,12 @@ export interface HolyLoaderProps {
* Default: "ltr"
*/
dir?: 'ltr' | 'rtl';
+
+ /**
+ * Specifies the delay in milliseconds before starting the progress bar.
+ * Default: 0 milliseconds
+ */
+ delay?: number;
}
/**
@@ -104,9 +110,11 @@ const HolyLoader = ({
boxShadow = DEFAULTS.boxShadow,
showSpinner = DEFAULTS.showSpinner,
ignoreSearchParams = DEFAULTS.ignoreSearchParams,
- dir = DEFAULTS.dir,
+ dir = DEFAULTS.dir,
+ delay = 0,
}: HolyLoaderProps): null => {
const holyProgressRef = React.useRef(null);
+ const delayTimeoutRef = React.useRef(null);
React.useEffect(() => {
const startProgress = (): void => {
@@ -212,7 +220,11 @@ const HolyLoader = ({
return;
}
- startProgress();
+ if (delay > 0) {
+ delayTimeoutRef.current = setTimeout(startProgress, delay);
+ } else {
+ startProgress();
+ }
} catch (error) {
stopProgress();
}
@@ -229,7 +241,7 @@ const HolyLoader = ({
zIndex,
boxShadow,
showSpinner,
- dir
+ dir,
});
}
@@ -243,8 +255,12 @@ const HolyLoader = ({
document.removeEventListener('click', handleClick);
document.removeEventListener(START_HOLY_EVENT, startProgress);
document.removeEventListener(STOP_HOLY_EVENT, stopProgress);
+
+ if (delayTimeoutRef.current !== null) {
+ clearTimeout(delayTimeoutRef.current);
+ }
};
- }, [holyProgressRef]);
+ }, [holyProgressRef, delay]);
return null;
};