UNPKG

use-elevator

Version:

A React hook for smooth scrolling that transforms boring scroll-to-top actions into playful elevator experiences with customizable settings

196 lines (131 loc) 6.78 kB
# useElevator A React hook for smooth scrolling. Inspired by [Elevator.js](https://tholman.com/elevator.js/). ## Installation ```bash npm install use-elevator ``` or using yarn: ```bash yarn add use-elevator ``` ## Features - Smooth scrolling to the top of the page or a specified element - Customizable animation duration - Callback functions for scroll start and end - TypeScript support ## How It Works The `useElevator` hook is designed to create a smooth, pleasant scrolling experience. Here's a detailed breakdown of how it works: ### Core Animation 1. **Animation Loop**: The hook uses `requestAnimationFrame` to create a smooth animation loop that updates the scroll position on each frame. 2. **Easing Function**: Rather than linear scrolling, the hook uses a quadratic easing function (`easeInOutQuad`) that starts slow, accelerates in the middle, and decelerates at the end - mimicking a real elevator's movement. 3. **Duration Calculation**: If no duration is provided, the hook automatically calculates an appropriate duration based on the scroll distance - longer distances get proportionally longer durations (with a maximum cap). ### DOM Handling 1. **Target Element Resolution**: When a target element ID is provided, the hook calculates its position by traversing the DOM, accounting for nested offset parents. 2. **Vertical Padding**: You can add padding to stop before the target element (useful for fixed headers). 3. **Window Blur Handling**: If the user switches tabs during animation, the hook gracefully jumps to the destination. ### Performance Optimizations 1. **Refs for State**: The hook uses React refs to store animation state, avoiding unnecessary re-renders during the animation. 2. **Dependency Optimization**: `useCallback` dependencies are minimized to prevent function recreation. 3. **Memory Management**: All resources are properly cleaned up on unmount, including animation frames. ### Safety Features 1. **Error Handling**: The hook contains comprehensive error handling around DOM operations. 2. **Type Safety**: Built with TypeScript, providing complete type definitions for all options and return values. 3. **Restart Prevention**: The hook prevents starting multiple elevator animations simultaneously. ### Event Handling 1. **Callbacks**: The hook provides `startCallback` and `endCallback` options to execute custom code at the beginning and end of the animation. 2. **State Management**: The hook provides an `isElevating` state that components can use to update UI accordingly. The combination of these features creates a delightful scrolling experience that stands out from typical "back to top" buttons, adding personality to your application while still being fully functional. ## Architecture The useElevator hook is designed with a modular architecture for maintainability and testability: ``` lib/ ├── utils/ │ └── animation.ts # Animation utility functions ├── types.ts # TypeScript interfaces ├── useElevator.ts # Main hook implementation └── index.ts # Public exports ``` ### Core Components: 1. **Main Hook (useElevator.ts)** - React hook that coordinates the scrolling animation - Manages state and lifecycle events - Handles user interactions 2. **Animation Utilities (utils/animation.ts)** - Provides easing functions for smooth scrolling - Calculates element positions and scroll distances - Determines optimal animation durations 3. **Type Definitions (types.ts)** - TypeScript interfaces for hook options and returns - Ensures type safety across the library This modular approach allows for: - Easy testing of individual components - Clear separation of concerns - Simplified maintenance and future enhancements ## Basic Usage ```jsx import { useElevator } from "use-elevator"; function ScrollToTopButton() { const { startElevating, isElevating } = useElevator({ duration: 2000, }); return ( <button onClick={startElevating} disabled={isElevating}> {isElevating ? "Going up..." : "Back to top"} </button> ); } ``` ## API Reference ### Options | Property | Type | Default | Description | | --------------- | -------- | --------- | ----------------------------------------------------------------------------------------------------------------------- | | targetElement | string | undefined | The ID of the element to scroll to. If not provided, scrolls to the top of the page. | | duration | number | 0 (auto) | Duration of the scroll animation in milliseconds. If not provided, the duration is calculated based on scroll distance. | | verticalPadding | number | 0 | Padding from the target element to stop above it. | | startCallback | function | undefined | Function to call when scrolling starts. | | endCallback | function | undefined | Function to call when scrolling ends. | ### Returns | Property | Type | Description | | -------------- | -------- | ------------------------------------------------- | | startElevating | function | Function to trigger the scroll animation. | | isElevating | boolean | Whether the scroll animation is currently active. | ## Examples ### Scroll to Specific Element ```jsx const { startElevating } = useElevator({ targetElement: "contact-section", verticalPadding: 20, }); ``` ### With Callbacks ```jsx const { startElevating } = useElevator({ startCallback: () => console.log("Starting elevator ride"), endCallback: () => console.log("Arrived at destination"), }); ``` ## Advanced Usage ### Multiple Elevator Instances You can create multiple elevator instances with different configurations: ```jsx function App() { // Elevator to the top of the page const topElevator = useElevator({ duration: 2000, }); // Elevator to a specific section const sectionElevator = useElevator({ targetElement: "contact-section", verticalPadding: 80, }); return ( <div> <button onClick={topElevator.startElevating}>Back to Top</button> <button onClick={sectionElevator.startElevating}>Jump to Contact</button> </div> ); } ``` ## License This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. MIT © [Bilal Mansuri](https://github.com/bilal-23)