Skip to content

Instantly share code, notes, and snippets.

@hexadeciman
Last active October 8, 2024 21:42
Show Gist options
  • Save hexadeciman/97948f8cc0c95a7e522acec4da7549e3 to your computer and use it in GitHub Desktop.
Save hexadeciman/97948f8cc0c95a7e522acec4da7549e3 to your computer and use it in GitHub Desktop.
useHighlight - a hook that allows you to highlight new functionalities
/* Backdrop fade in/out */
.highlight-backdrop {
@apply fixed inset-0 bg-black bg-opacity-50 transition-opacity duration-300 opacity-0 pointer-events-none;
z-index: 1000;
}
.backdrop-visible {
@apply opacity-100 pointer-events-auto; /* Show the backdrop */
}
/* Got it button fade in/out */
.got-it-button {
@apply absolute bg-gray-200 text-black font-semibold px-4 py-2 rounded-full transition-opacity duration-300 opacity-0 pointer-events-none;
z-index: 1001;
}
.button-visible {
@apply opacity-100 pointer-events-auto; /* Show the button */
}
/* Positioning logic based on props */
.top {
@apply top-0 left-1/2 transform -translate-x-1/2 mt-4;
}
.top-right {
@apply top-0 right-0 mt-4 mr-4;
}
.bottom {
@apply bottom-0 left-1/2 transform -translate-x-1/2 mb-4;
}
.bottom-right {
@apply bottom-[-50px] right-0;
}
import { useEffect, useState, RefObject } from 'react';
import './useHighlight.scss';
type Position = 'top' | 'bottom' | 'bottom-right' | 'top-right';
interface UseHighlightProps {
elementRef: RefObject<HTMLElement>; // Ref to the element you want to highlight
position?: Position; // Position of the dismiss button
buttonMessage?: string; // Text for the "Got it" button
open?: boolean; // Whether the highlight should be open or closed
onDismiss?: () => void; // Callback when the highlight is dismissed
}
export const useHighlight = ({
elementRef,
position = 'top',
buttonMessage = 'Got it',
open = false,
onDismiss,
}: UseHighlightProps) => {
const [isVisible, setIsVisible] = useState(open);
useEffect(() => {
setIsVisible(open);
}, [open]);
useEffect(() => {
if (!elementRef.current || !isVisible) return;
const element = elementRef.current;
// Set the element on top of everything
element.style.position = 'relative';
element.style.zIndex = '1001';
// Create and add the backdrop
const backdrop = document.createElement('div');
backdrop.className = 'highlight-backdrop';
document.body.appendChild(backdrop);
// Create and add the "Got it" button
const gotItButton = document.createElement('button');
gotItButton.innerText = buttonMessage;
gotItButton.className = `got-it-button ${position}`;
gotItButton.onclick = () => {
// Fade out both the backdrop and button before removal
backdrop.classList.remove('backdrop-visible');
gotItButton.classList.remove('button-visible');
setTimeout(() => {
setIsVisible(false); // Hide button after animation completes
onDismiss?.(); // Call the dismiss callback if it exists
}, 300); // Match the duration of the transition
};
// Append button to the target element
element.appendChild(gotItButton);
// Trigger the fade-in by adding the visibility classes
setTimeout(() => {
backdrop.classList.add('backdrop-visible');
gotItButton.classList.add('button-visible');
}, 10); // Ensure transition applies
// Cleanup function when component unmounts
return () => {
backdrop.remove();
gotItButton.remove();
element.style.zIndex = ''; // Reset z-index
};
}, [elementRef, isVisible, position, buttonMessage, onDismiss]);
return { isVisible, setIsVisible };
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment