UNPKG

@replyke/core

Version:

Replyke: Build interactive apps with social features like comments, votes, feeds, user lists, notifications, and more.

136 lines 5.42 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const react_1 = require("react"); const useFetchUserSuggestions_1 = __importDefault(require("./useFetchUserSuggestions")); const handleError_1 = require("../../utils/handleError"); function escapeRegex(str) { return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } const useUserMentions = ({ content, setContent, focus, cursorPosition, isSelectionActive, trigger = "@", minChars = 3, debounceDelay = 1000, validPattern = "[\\w.]+", }) => { const fetchMentionSuggestions = (0, useFetchUserSuggestions_1.default)(); const [loadingState, setLoadingState] = (0, react_1.useState)(false); const [mentions, setMentions] = (0, react_1.useState)([]); const [isMentionActive, setIsMentionActive] = (0, react_1.useState)(false); const [mentionTrigger, setMentionTrigger] = (0, react_1.useState)(""); const [mentionSuggestions, setMentionSuggestions] = (0, react_1.useState)([]); const debounceTimerRef = (0, react_1.useRef)(null); const resetMentions = () => { setMentions([]); setIsMentionActive(false); setMentionTrigger(""); setMentionSuggestions([]); setLoadingState(false); }; const addMention = (user) => { if (!user.username) throw new Error("User has no username set"); setMentions((prevMentions) => { // Check if the user already exists based on id if (prevMentions.some((mention) => mention.id === user.id)) { return prevMentions; // Return the previous mentions if the user already exists } // Add the new mention if it doesn't already exist return [ ...prevMentions, { id: user.id, foreignId: user.foreignId, username: user.username, type: "user", }, ]; }); }; const handleMentionClick = (user) => { const mentionRegex = new RegExp(`${escapeRegex(trigger)}${escapeRegex(mentionTrigger)}(\\s|$)`); setContent(content.replace(mentionRegex, `${trigger}${user.username} `)); addMention(user); setIsMentionActive(false); setMentionTrigger(""); setMentionSuggestions([]); setLoadingState(false); focus(); }; const handleFetchMentionSuggestions = (0, react_1.useCallback)(async (query) => { try { const suggestions = await fetchMentionSuggestions({ query }); if (suggestions && suggestions.length > 0) { setMentionSuggestions(suggestions); // Replace with fetched data } else { setMentionSuggestions([]); setIsMentionActive(false); } } catch (err) { (0, handleError_1.handleError)(err, "Error fetching mentions"); } finally { setLoadingState(false); // Set to false after data is fetched } }, [fetchMentionSuggestions]); (0, react_1.useEffect)(() => { let start = cursorPosition - 1; // Move backward from cursor to find the word directly before the cursor while (start >= 0 && content[start] !== " ") { start--; } // Extract potential trigger word (start + 1 because `start` is on the space) const potentialTrigger = content.slice(start + 1, cursorPosition); const validMentionPattern = new RegExp("^" + escapeRegex(trigger) + validPattern + "$"); if (!isSelectionActive && validMentionPattern.test(potentialTrigger) && potentialTrigger.length >= trigger.length + minChars) { const triggerText = potentialTrigger.slice(trigger.length); setMentionTrigger(triggerText); setIsMentionActive(true); setLoadingState(true); // Clear the previous debounce timer if (debounceTimerRef.current) { clearTimeout(debounceTimerRef.current); } // Set a new debounce timer debounceTimerRef.current = setTimeout(() => { handleFetchMentionSuggestions(triggerText); }, debounceDelay); } else { if (debounceTimerRef.current) { clearTimeout(debounceTimerRef.current); } setMentionTrigger(""); setIsMentionActive(false); setMentionSuggestions([]); setLoadingState(false); } // Cleanup on component unmount to clear any remaining timer return () => { if (debounceTimerRef.current) { clearTimeout(debounceTimerRef.current); } }; }, [ cursorPosition, isSelectionActive, handleFetchMentionSuggestions, content, trigger, minChars, debounceDelay, validPattern, ]); return { isMentionActive, loading: loadingState, mentionSuggestions, handleMentionClick, mentions, addMention, resetMentions, }; }; exports.default = useUserMentions; //# sourceMappingURL=useUserMentions.js.map