material-you-react/src/primitive-components/ripple/ripple-area.tsx

114 lines
3.7 KiB
TypeScript
Raw Normal View History

2024-01-25 22:43:42 +03:00
"use client"
import React, {
useId,
useRef,
useState,
forwardRef,
useCallback,
useImperativeHandle
} from 'react';
import {Ripple} from "./ripple";
import {Ripples} from "./ripple";
import {RippleAreaProps} from "./ripple.types";
const TIMEOUT : number = 550;
const rippleAreaContext = React.createContext(false);
const RippleArea = forwardRef(
function RippleArea({central = false, callback, ...props} : RippleAreaProps, ref) {
2024-01-25 22:43:42 +03:00
const [ripples, setRipples] = useState<Array<JSX.Element>>([]),
rippleDomain = useRef<any>(null),
clicked = useRef<boolean>(false),
uniqueKey = useRef<number>(0),
uniqueId = useId();
let classes = props.className ?
`m3 m3-ripple-domain ${props.className}`.trimEnd() :
"m3 m3-ripple-domain";
const start = useCallback((event : any, cb : (state : boolean) => void) : void => {
clicked.current = true;
cb(clicked.current);
const rippleDomainChar = rippleDomain.current ? rippleDomain.current.getBoundingClientRect() : {
width: 0,
height: 0,
left: 0,
top: 0,
}
let rippleX : number = !central ? event.clientX - rippleDomainChar.left : rippleDomainChar.width / 2,
rippleY : number = !central ? event.clientY - rippleDomainChar.top : rippleDomainChar.height / 2,
2024-01-25 22:43:42 +03:00
rippleSizeX : number = Math.max(Math.abs(rippleDomainChar.width - rippleX), rippleX) * 2 + 2,
rippleSizeY : number = Math.max(Math.abs(rippleDomainChar.height - rippleY), rippleY) * 2 + 2,
rippleS : number = (rippleSizeX ** 2 + rippleSizeY ** 2) ** 0.5;
setRipples((prevRipples : Array<JSX.Element>) => {
if(prevRipples.length === 0){
return [
<Ripple rippleX={rippleX}
rippleY={rippleY}
rippleS={rippleS}
key={uniqueKey.current}
lifetime={TIMEOUT}/>
]
} else {
let old = [...prevRipples];
old.push(
<Ripple rippleX={rippleX}
rippleY={rippleY}
rippleS={rippleS}
key={uniqueKey.current}
lifetime={TIMEOUT}/>
)
return old;
}
}
)
uniqueKey.current += 1;
}, []);
const stop = useCallback((_event : any, cb : (state : boolean) => void) => {
clicked.current = false;
cb(clicked.current);
setRipples((prevRipples : Array<JSX.Element>) => {
if(prevRipples.length > 0) {
let old = [...prevRipples];
old.shift();
return old;
}
return prevRipples
});
},[]);
useImperativeHandle(ref, () => ({
start,
stop,
}), [start, stop]);
return (
<span className={classes}
id={uniqueId}
ref={rippleDomain}>
<rippleAreaContext.Provider value={clicked.current}>
<Ripples>
{ripples}
</Ripples>
</rippleAreaContext.Provider>
</span>
);
}
)
export {rippleAreaContext, RippleArea};