Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added manual control possibility over holy loader #25

Merged
merged 6 commits into from
Apr 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,28 @@ export default function RootLayout({ children }) {
}
```

### Programmatic Control (Client Components)

Have an async operation before an eventual route change? You might be interested in holy-loader's manual controls. These only work in client components!

```typescript
'use client';

import { startHolyLoader, stopHolyLoader } from 'holy-loader';

try {
startHolyLoader(); // Trigger the loader beforehand
await signOut(); // Example async operation
} catch (error) {
stopHolyLoader(); // Stop the loader on error
// Handle the error
} finally {
stopHolyLoader(); // Stop the loader after the operation, and potentially do something else
/* OR */
router.push('/'); // Navigate to the desired route, which will automatically stop the loader
}
```

## Common issues

Prevent triggering the loader when clicking a Button within a Next link:
Expand Down
14 changes: 7 additions & 7 deletions src/HolyProgress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,23 +184,23 @@ export class HolyProgress {
* @public
* @returns {HolyProgress} The current instance for chaining methods.
*/
public start = (): HolyProgress => {
public readonly start = (): HolyProgress => {
if (this.status === null) {
this.setTo(0);
}

this.startTrickle();
this.startTrickle();

if (this.settings.showSpinner === true) {
this.createSpinner();
if (this.settings.showSpinner === true) {
this.createSpinner();
}
}

return this;
};

/**
* Performs automatic incrementation of the progress bar.
* This function is recursive and continues to increment the progress at intervals defined by `sppeed`.
* This function is recursive and continues to increment the progress at intervals defined by `speed`.
* @private
*/
private readonly startTrickle = (): void => {
Expand All @@ -219,7 +219,7 @@ export class HolyProgress {
* @public
* @returns {HolyProgress} The current instance for chaining methods.
*/
public complete = (): HolyProgress => this.setTo(1);
public readonly complete = (): HolyProgress => this.setTo(1);

/**
* Calculates an increment value based on the current status of the progress.
Expand Down
3 changes: 3 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,6 @@ export const DEFAULTS = {
showSpinner: false,
boxShadow: undefined,
};

export const START_HOLY_EVENT = 'holy-progress-start';
export const STOP_HOLY_EVENT = 'holy-progress-stop';
60 changes: 44 additions & 16 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import * as React from 'react';
import { HolyProgress } from './HolyProgress';
import { DEFAULTS } from './constants';
import { DEFAULTS, START_HOLY_EVENT, STOP_HOLY_EVENT } from './constants';

export interface HolyLoaderProps {
/**
Expand Down Expand Up @@ -97,6 +97,20 @@ export const isSameHost = (currentUrl: string, newUrl: string): boolean => {
);
};

/**
* Dispatches the event to manually start the HolyLoader progress bar.
*/
export const startHolyLoader = (): void => {
document.dispatchEvent(new Event(START_HOLY_EVENT));
};

/**
* Dispatches the event to manually stop the HolyLoader progress bar.
*/
export const stopHolyLoader = (): void => {
document.dispatchEvent(new Event(STOP_HOLY_EVENT));
};

/**
* HolyLoader is a React component that provides a customizable top-loading progress bar.
*
Expand All @@ -113,18 +127,26 @@ const HolyLoader = ({
boxShadow = DEFAULTS.boxShadow,
showSpinner = DEFAULTS.showSpinner,
}: HolyLoaderProps): null => {
React.useEffect(() => {
let holyProgress: HolyProgress;
const holyProgressRef = React.useRef<HolyProgress | null>(null);

React.useEffect(() => {
const startProgress = (): void => {
if (holyProgressRef.current === null) {
return;
}

try {
holyProgress.start();
holyProgressRef.current.start();
} catch (error) {}
};

const stopProgress = (): void => {
if (holyProgressRef.current === null) {
return;
}

try {
holyProgress.complete();
holyProgressRef.current.complete();
} catch (error) {}
};

Expand Down Expand Up @@ -192,25 +214,31 @@ const HolyLoader = ({
};

try {
holyProgress = new HolyProgress({
color,
height,
initialPosition,
easing,
speed,
zIndex,
boxShadow,
showSpinner,
});
if (holyProgressRef.current === null) {
holyProgressRef.current = new HolyProgress({
color,
height,
initialPosition,
easing,
speed,
zIndex,
boxShadow,
showSpinner,
});
}

document.addEventListener('click', handleClick);
document.addEventListener(START_HOLY_EVENT, startProgress);
document.addEventListener(STOP_HOLY_EVENT, stopProgress);
stopProgressOnHistoryUpdate();
} catch (error) {}

return () => {
document.removeEventListener('click', handleClick);
document.removeEventListener(START_HOLY_EVENT, startProgress);
document.removeEventListener(STOP_HOLY_EVENT, stopProgress);
};
}, []);
}, [holyProgressRef]);

return null;
};
Expand Down