@replyke/core
Version:
Replyke: Build interactive apps with social features like comments, votes, feeds, user lists, notifications, and more.
136 lines • 5.42 kB
JavaScript
;
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