@gfazioli/mantine-onboarding-tour
Version:
A Mantine 9 onboarding tour component with focus-reveal overlays, cutout highlights, step-by-step popover navigation, and compound components for guided user experiences.
73 lines (69 loc) • 2.22 kB
JavaScript
'use client';
;
var React = require('react');
function buildCutoutPath(vw, vh, rect, padding, radius) {
const x = rect.x - padding;
const y = rect.y - padding;
const w = rect.width + padding * 2;
const h = rect.height + padding * 2;
const r = Math.min(radius, w / 2, h / 2);
return [
`M0,0 H${vw} V${vh} H0 Z`,
`M${x + r},${y}`,
`H${x + w - r}`,
`Q${x + w},${y} ${x + w},${y + r}`,
`V${y + h - r}`,
`Q${x + w},${y + h} ${x + w - r},${y + h}`,
`H${x + r}`,
`Q${x},${y + h} ${x},${y + h - r}`,
`V${y + r}`,
`Q${x},${y} ${x + r},${y}`,
`Z`
].join(" ");
}
function useCutoutRect(active, stepId) {
const [state, setState] = React.useState(null);
const measure = React.useCallback(() => {
const el = document.querySelector("[data-onboarding-tour-focus-reveal-focused]");
if (el) {
const r = el.getBoundingClientRect();
const vw = window.innerWidth;
const vh = window.innerHeight;
setState((prev) => {
if (prev && prev.rect.x === r.x && prev.rect.y === r.y && prev.rect.width === r.width && prev.rect.height === r.height && prev.vw === vw && prev.vh === vh) {
return prev;
}
return { rect: { x: r.x, y: r.y, width: r.width, height: r.height }, vw, vh };
});
} else {
setState(null);
}
}, []);
React.useEffect(() => {
if (!active) {
setState(null);
return void 0;
}
let rafId = 0;
const onUpdate = () => {
cancelAnimationFrame(rafId);
rafId = requestAnimationFrame(measure);
};
const poll = setInterval(onUpdate, 50);
const stopPoll = setTimeout(() => clearInterval(poll), 1500);
window.addEventListener("scroll", onUpdate, true);
window.addEventListener("resize", onUpdate);
onUpdate();
return () => {
cancelAnimationFrame(rafId);
clearInterval(poll);
clearTimeout(stopPoll);
window.removeEventListener("scroll", onUpdate, true);
window.removeEventListener("resize", onUpdate);
};
}, [active, stepId, measure]);
return state;
}
exports.buildCutoutPath = buildCutoutPath;
exports.useCutoutRect = useCutoutRect;
//# sourceMappingURL=use-cutout-rect.cjs.map