mirror of
https://github.com/makeplane/plane.git
synced 2025-12-21 14:19:38 +01:00
[WIKI-509] feat: comment copy link option (#7385)
* feat: comment copy link option * chore: add translations * chore: update block position * chore: rename use id scroll hook * refactor: setTimeout function * refactor: use-hash-scroll hook
This commit is contained in:
committed by
GitHub
parent
f90e553881
commit
2c70c1aaa8
128
packages/hooks/src/use-hash-scroll.ts
Normal file
128
packages/hooks/src/use-hash-scroll.ts
Normal file
@@ -0,0 +1,128 @@
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
|
||||
type TArgs = {
|
||||
elementId: string;
|
||||
pathname: string;
|
||||
scrollDelay?: number;
|
||||
};
|
||||
|
||||
type TReturnType = {
|
||||
isHashMatch: boolean;
|
||||
hashIds: string[];
|
||||
scrollToElement: () => boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* Custom hook for handling hash-based scrolling to a specific element
|
||||
* Supports multiple IDs in URL hash (comma-separated, space-separated, or other delimiters)
|
||||
*
|
||||
* @param {TArgs} args - The ID of the element to scroll to
|
||||
* @returns {TReturnType} Object containing hash match status and scroll function
|
||||
*/
|
||||
export const useHashScroll = (args: TArgs): TReturnType => {
|
||||
const { elementId, pathname, scrollDelay = 200 } = args;
|
||||
// State to track if the current hash contains the provided element ID
|
||||
const [isHashMatch, setIsHashMatch] = useState(false);
|
||||
// State to track all IDs found in the hash
|
||||
const [hashIds, setHashIds] = useState<string[]>([]);
|
||||
|
||||
/**
|
||||
* Scrolls to the element with the provided ID
|
||||
* @returns {boolean} - Whether the scroll was successful
|
||||
*/
|
||||
const scrollToElement = useCallback((): boolean => {
|
||||
try {
|
||||
const element = document.getElementById(elementId);
|
||||
|
||||
if (element) {
|
||||
setTimeout(() => {
|
||||
element.scrollIntoView({
|
||||
behavior: "smooth",
|
||||
block: "center",
|
||||
});
|
||||
}, scrollDelay);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
} catch (error) {
|
||||
console.warn("Hash scroll error:", error);
|
||||
return false;
|
||||
}
|
||||
}, [elementId, scrollDelay]);
|
||||
|
||||
/**
|
||||
* Extracts multiple IDs from hash string
|
||||
* Supports various delimiters: comma, space, pipe, semicolon
|
||||
* @param {string} hashString - The hash part of the URL
|
||||
* @returns {string[]} - Array of clean ID strings
|
||||
*/
|
||||
const extractIdsFromHash = (hashString: string | null): string[] => {
|
||||
if (!hashString) return [];
|
||||
|
||||
// Split by common delimiters and clean up
|
||||
return hashString
|
||||
.split(/[,\s|;]+/) // Split by comma, space, pipe, or semicolon
|
||||
.map((id) => id.trim()) // Remove whitespace
|
||||
.filter((id) => id.length > 0); // Remove empty strings
|
||||
};
|
||||
|
||||
/**
|
||||
* Get current hash from window.location
|
||||
* @returns {string | null} - Current hash without the # symbol
|
||||
*/
|
||||
const getCurrentHash = (): string | null => {
|
||||
if (typeof window === "undefined") return null;
|
||||
const hash = window.location.hash;
|
||||
return hash ? hash.slice(1) : null; // Remove the # symbol
|
||||
};
|
||||
|
||||
// Effect to handle hash changes and initial load
|
||||
useEffect(() => {
|
||||
if (!elementId) {
|
||||
setIsHashMatch(false);
|
||||
setHashIds([]);
|
||||
return;
|
||||
}
|
||||
|
||||
const handleHashChange = () => {
|
||||
const hash = getCurrentHash();
|
||||
|
||||
// Extract all IDs from the hash
|
||||
const idsInHash = extractIdsFromHash(hash);
|
||||
setHashIds(idsInHash);
|
||||
|
||||
// Check if provided element ID is present in the hash
|
||||
const hashMatches = idsInHash.includes(elementId);
|
||||
setIsHashMatch(hashMatches);
|
||||
|
||||
// If hash matches, attempt to scroll to the element
|
||||
if (hashMatches) {
|
||||
scrollToElement();
|
||||
}
|
||||
};
|
||||
|
||||
// Handle initial load
|
||||
handleHashChange();
|
||||
|
||||
// Listen for hash changes
|
||||
window.addEventListener("hashchange", handleHashChange);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("hashchange", handleHashChange);
|
||||
};
|
||||
}, [elementId, pathname, scrollToElement]); // Include pathname to handle route changes
|
||||
|
||||
// Return object with hash match status and utility functions
|
||||
return {
|
||||
// Whether the current URL hash contains the provided element ID
|
||||
isHashMatch,
|
||||
|
||||
// Array of all IDs found in the current hash
|
||||
hashIds,
|
||||
|
||||
// Manually trigger scroll to the element
|
||||
scrollToElement,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user