I wonder if there is a way to achieve a structure like this:
1 .full window dimensions mask rect that will prevent pointer events
2. multiple rects with clip path that will create spots that can be clicked (html structure under mask)
It’s possible for a single element with a polygon, but no idea how to make it work with multiple dynamic rects (some way of generating polygon from rects, or is there a way to achieve it in other way without svg)
codepen:
https://codepen.io/mza/pen/poByzre?editors=1111
`
const getWindow = () => ({ w: window.innerWidth, h: window.innerHeight });
function uniqueId(prefix: string) {
return prefix + Math.random().toString(36).substring(2, 16);
}
const Mask = ({ sizes }) => {
const maskID = uniqueId('mask__');
const clipID = uniqueId('clip__');
const { w, h } = getWindow();
const width = sizes[0]?.width;
const height =sizes[0]?.heigh;
const top = sizes[0]?.top;
const left = sizes[0]?.left;
const windowWidth = w;
const windowHeight = h;
return (
<div
style={{
opacity: 0.7,
left: 0,
top: 0,
position: 'fixed',
zIndex: 999,
pointerEvents: 'none',
color: '#000',
}}
>
<svg
width={windowWidth}
height={windowHeight}
xmlns="http://www.w3.org/2000/svg"
style={{
width: windowWidth,
height: windowHeight,
left: 0,
top: 0,
position: 'fixed',
}}
>
<defs>
<mask id={maskID}>
<rect x={0} y={0} width={windowWidth} height={windowHeight} fill="white" />
{sizes.map(({ width, height, top, left }, index) => {
return (
<rect
key={index}
x={left}
y={top}
style={{
width,
height,
fill: 'black',
transition: 'width 0.1s, height 0.1s',
}}
/>
);
})}
</mask>
<clipPath id={clipID}>
</clipPath>
</defs>
<rect
x={0}
y={0}
style={{
width: windowWidth,
height: windowHeight,
fill: 'currentColor',
mask: `url(#${maskID})`,
pointerEvents: 'none',
}}
/>
<rect
x={0}
y={0}
style={{
width: windowWidth,
height: windowHeight,
fill: 'currentcolor',
pointerEvents: 'auto',
clipPath: `url(#${clipID})`,
}}
/>
</svg>
</div>
);
};
const sizes = [
{
width: 50,
height:50,
top: 100,
left: 100
},
{
width: 50,
height:50,
top: 100,
left: 200
}
];
const App = () => {
return (
<>
<div
onClick={() => {
alert('clicked');
}}
style={{
width: "100vw",
height: "100vh"
}}
></div>
<Mask sizes={sizes} />
</>
)
}
const container = document.getElementById('root');
const root = ReactDOM.createRoot(container);
root.render(<App/>);
`