react-pattern-lock-ts
Version:
PatternLock is a lightweight and customizable React component for implementing a secure and interactive pattern lock system. Perfect for authentication, games, or creative applications, it supports touch and mouse interactions with real-time state updates
76 lines (75 loc) • 3.18 kB
JavaScript
'use client';
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useEffect } from 'react';
import './style.css';
import { useRef, useState } from 'react';
const PatternLock = ({ className, numberClassName, bgClassName, setPatterns, useNumber = false, resetStyleByChange, }) => {
const [resArr, setResArr] = useState([]);
const [isDrawing, setIsDrawing] = useState(false);
const containerRef = useRef(null);
const parentBulletRef = useRef(null);
const resetBullets = () => {
setResArr([]);
};
const getNumberFromPoint = (x, y) => {
const element = document.elementFromPoint(x, y);
const cls = `.${className ? className : 'bullet-bYMyWeb'}`;
const bullet = element?.closest(cls);
if (bullet) {
const index = Array.from(document.querySelectorAll(cls)).indexOf(bullet);
return index;
}
return null;
};
const startPattern = (num) => {
if (!isDrawing) {
setIsDrawing(true);
setResArr([num]);
}
};
const movePattern = (num) => {
if (isDrawing && !resArr.includes(num)) {
setResArr((prev) => [...prev, num]);
}
};
const endPattern = () => {
if (isDrawing) {
setIsDrawing(false);
if (resArr.length > 0) {
setPatterns((prev) => [...prev, resArr]);
}
}
};
// Mouse Events
const handleMouseDown = (num) => {
// setResArr([]);
startPattern(num);
};
const handleMouseMove = (num) => {
if (isDrawing) {
movePattern(num);
}
};
// Touch Events
const handleTouchStart = (num) => {
// setResArr([]);
startPattern(num);
};
const handleTouchMove = (e) => {
if (!isDrawing)
return null;
const touch = e.touches[0];
const rect = e.currentTarget.getBoundingClientRect();
const x = touch.clientX - rect.left;
const y = touch.clientY - rect.top;
const num = getNumberFromPoint(touch.clientX, touch.clientY);
if (num !== null) {
movePattern(num);
}
};
useEffect(() => {
resetBullets();
}, [resetStyleByChange]);
return (_jsx("section", { ref: containerRef, onMouseUp: endPattern, onMouseLeave: endPattern, onTouchEnd: endPattern, onTouchCancel: endPattern, className: 'pattern-content-bYMyWeb', children: _jsxs("div", { ref: parentBulletRef, className: 'bullet-content-bYMyWeb', children: [_jsx("div", { onMouseDown: resetBullets, onTouchStart: resetBullets, className: `bg-z-index-bYMyWeb ${bgClassName ? bgClassName : 'bg-bYMyWeb'}` }), [0, 1, 2, 3, 4, 5, 6, 7, 8].map((item) => (_jsx("div", { onMouseDown: (e) => handleMouseDown(item), onMouseMove: (e) => handleMouseMove(item), onTouchStart: (e) => handleTouchStart(item), onTouchMove: handleTouchMove, className: `${className ? className : 'bullet-bYMyWeb'} ${resArr.includes(item) ? 'active-bullet-bYMyWeb' : ''}`, children: useNumber && _jsx("span", { className: numberClassName, children: item }) }, item)))] }) }));
};
export default PatternLock;