@arolariu/components
Version:
🎨 60+ beautiful, accessible React components built on Radix UI. TypeScript-first, tree-shakeable, SSR-ready. Perfect for modern web apps, design systems & rapid prototyping. Zero config, maximum flexibility! ⚡
179 lines (178 loc) • 7.24 kB
JavaScript
"use client";
;
var __webpack_require__ = {};
(()=>{
__webpack_require__.d = (exports1, definition)=>{
for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
enumerable: true,
get: definition[key]
});
};
})();
(()=>{
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
})();
(()=>{
__webpack_require__.r = (exports1)=>{
if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
value: 'Module'
});
Object.defineProperty(exports1, '__esModule', {
value: true
});
};
})();
var __webpack_exports__ = {};
__webpack_require__.r(__webpack_exports__);
__webpack_require__.d(__webpack_exports__, {
Scratcher: ()=>Scratcher
});
const jsx_runtime_namespaceObject = require("react/jsx-runtime");
const utils_cjs_namespaceObject = require("../../lib/utils.cjs");
const react_namespaceObject = require("motion/react");
const external_react_namespaceObject = require("react");
const Scratcher = ({ width, height, minScratchPercentage = 50, onComplete, children, className, gradientColors = [
"#A97CF8",
"#F38CB8",
"#FDCC92"
] })=>{
const canvasRef = (0, external_react_namespaceObject.useRef)(null);
const [isScratching, setIsScratching] = (0, external_react_namespaceObject.useState)(false);
const [isComplete, setIsComplete] = (0, external_react_namespaceObject.useState)(false);
const controls = (0, react_namespaceObject.useAnimation)();
(0, external_react_namespaceObject.useEffect)(()=>{
const canvas = canvasRef.current;
const ctx = canvas?.getContext("2d");
if (canvas && ctx) {
ctx.fillStyle = "#ccc";
ctx.fillRect(0, 0, canvas.width, canvas.height);
const gradient = ctx.createLinearGradient(0, 0, canvas.width, canvas.height);
gradient.addColorStop(0, gradientColors[0]);
gradient.addColorStop(0.5, gradientColors[1]);
gradient.addColorStop(1, gradientColors[2]);
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
}, [
gradientColors
]);
(0, external_react_namespaceObject.useEffect)(()=>{
const handleDocumentMouseMove = (event)=>{
if (!isScratching) return;
scratch(event.clientX, event.clientY);
};
const handleDocumentTouchMove = (event)=>{
if (!isScratching) return;
const touch = event.touches[0];
scratch(touch.clientX, touch.clientY);
};
const handleDocumentMouseUp = ()=>{
setIsScratching(false);
checkCompletion();
};
const handleDocumentTouchEnd = ()=>{
setIsScratching(false);
checkCompletion();
};
document.addEventListener("mousedown", handleDocumentMouseMove);
document.addEventListener("mousemove", handleDocumentMouseMove);
document.addEventListener("touchstart", handleDocumentTouchMove);
document.addEventListener("touchmove", handleDocumentTouchMove);
document.addEventListener("mouseup", handleDocumentMouseUp);
document.addEventListener("touchend", handleDocumentTouchEnd);
document.addEventListener("touchcancel", handleDocumentTouchEnd);
return ()=>{
document.removeEventListener("mousedown", handleDocumentMouseMove);
document.removeEventListener("mousemove", handleDocumentMouseMove);
document.removeEventListener("touchstart", handleDocumentTouchMove);
document.removeEventListener("touchmove", handleDocumentTouchMove);
document.removeEventListener("mouseup", handleDocumentMouseUp);
document.removeEventListener("touchend", handleDocumentTouchEnd);
document.removeEventListener("touchcancel", handleDocumentTouchEnd);
};
}, [
isScratching
]);
const handleMouseDown = ()=>setIsScratching(true);
const handleTouchStart = ()=>setIsScratching(true);
const scratch = (clientX, clientY)=>{
const canvas = canvasRef.current;
const ctx = canvas?.getContext("2d");
if (canvas && ctx) {
const rect = canvas.getBoundingClientRect();
const x = clientX - rect.left + 16;
const y = clientY - rect.top + 16;
ctx.globalCompositeOperation = "destination-out";
ctx.beginPath();
ctx.arc(x, y, 30, 0, 2 * Math.PI);
ctx.fill();
}
};
const startAnimation = async ()=>{
await controls.start({
scale: [
1,
1.5,
1
],
rotate: [
0,
10,
-10,
10,
-10,
0
],
transition: {
duration: 0.5
}
});
if (onComplete) onComplete();
};
const checkCompletion = ()=>{
if (isComplete) return;
const canvas = canvasRef.current;
const ctx = canvas?.getContext("2d");
if (canvas && ctx) {
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const pixels = imageData.data;
const totalPixels = pixels.length / 4;
let clearPixels = 0;
for(let i = 3; i < pixels.length; i += 4)if (0 === pixels[i]) clearPixels++;
const percentage = clearPixels / totalPixels * 100;
if (percentage >= minScratchPercentage) {
setIsComplete(true);
ctx.clearRect(0, 0, canvas.width, canvas.height);
startAnimation();
}
}
};
return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)(react_namespaceObject.motion.div, {
className: (0, utils_cjs_namespaceObject.cn)("relative select-none", className),
style: {
width,
height,
cursor: "url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMiIgaGVpZ2h0PSIzMiIgdmlld0JveD0iMCAwIDMyIDMyIj4KICA8Y2lyY2xlIGN4PSIxNiIgY3k9IjE2IiByPSIxNSIgc3R5bGU9ImZpbGw6I2ZmZjtzdHJva2U6IzAwMDtzdHJva2Utd2lkdGg6MXB4OyIgLz4KPC9zdmc+'), auto"
},
animate: controls,
children: [
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("canvas", {
ref: canvasRef,
width: width,
height: height,
className: "absolute left-0 top-0",
onMouseDown: handleMouseDown,
onTouchStart: handleTouchStart
}),
children
]
});
};
exports.Scratcher = __webpack_exports__.Scratcher;
for(var __webpack_i__ in __webpack_exports__)if (-1 === [
"Scratcher"
].indexOf(__webpack_i__)) exports[__webpack_i__] = __webpack_exports__[__webpack_i__];
Object.defineProperty(exports, '__esModule', {
value: true
});
//# sourceMappingURL=scratcher.cjs.map