parent
6ee10e0fa2
commit
3f027d9e51
|
@ -27,7 +27,7 @@ module.exports = {
|
|||
plugins: ['react'],
|
||||
rules: {
|
||||
// Possible errors
|
||||
'no-console': 'warn',
|
||||
'no-console': 'off',
|
||||
// Best practices
|
||||
'dot-notation': 'error',
|
||||
'no-else-return': 'error',
|
||||
|
@ -36,9 +36,10 @@ module.exports = {
|
|||
// Stylistic
|
||||
'array-bracket-spacing': 'error',
|
||||
'computed-property-spacing': ['error', 'never'],
|
||||
'@typescript-eslint/no-unused-vars': 'warn',
|
||||
curly: 'error',
|
||||
'no-lonely-if': 'error',
|
||||
'no-unneeded-ternary': 'error',
|
||||
'no-unneeded-ternary': 'warn',
|
||||
'one-var-declaration-per-line': 'error',
|
||||
quotes: [
|
||||
'error',
|
||||
|
|
|
@ -2,5 +2,6 @@
|
|||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="ES6PreferShortImport" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
</profile>
|
||||
</component>
|
|
@ -13,7 +13,7 @@ This repository is including and will be including components, enumerates in tab
|
|||
- [X] Switches
|
||||
- [ ] Chips
|
||||
- [x] Icon
|
||||
- [x] Ripples Effect
|
||||
- [x] Ripple Effect
|
||||
- [ ] Dividers (WIP)
|
||||
- [x] Badges
|
||||
- [ ] Select field
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
'use client';
|
||||
|
||||
import { bool, string } from 'prop-types';
|
||||
import { RippleArea } from '../../ripple/ripple-area';
|
||||
import { RippleEffect } from '../../ripple/ripple-effect';
|
||||
import { ButtonLayoutProps } from './button-layout.types';
|
||||
import useRippleEffect from '../../ripple/hooks/useRippleEffect';
|
||||
import React, { forwardRef, useId, useRef, useState } from 'react';
|
||||
|
@ -26,7 +26,7 @@ export const ButtonLayout = forwardRef<HTMLButtonElement, ButtonLayoutProps>(
|
|||
ref={ref}
|
||||
>
|
||||
{props.children}
|
||||
<RippleArea
|
||||
<RippleEffect
|
||||
callback={setIsActive}
|
||||
central={centralRipple}
|
||||
ref={ripplesRef}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
'use client';
|
||||
|
||||
import { RippleArea } from '../ripple/ripple-area';
|
||||
import { RippleEffect } from '../ripple/ripple-effect';
|
||||
import { CardActionAreaProps } from './card.types';
|
||||
import { forwardRef, useRef, useState } from 'react';
|
||||
import useRippleEffect from '../ripple/hooks/useRippleEffect';
|
||||
|
@ -29,7 +29,7 @@ export const CardActionArea = forwardRef<HTMLDivElement, CardActionAreaProps>(
|
|||
</div>
|
||||
<span className={'m3 m3-card-state-layer'} />
|
||||
{ripples && (
|
||||
<RippleArea
|
||||
<RippleEffect
|
||||
callback={setIsActive}
|
||||
central={centralRipple}
|
||||
ref={ripplesRef}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
export { Card } from './card/card';
|
||||
export { Icon } from './icon/icon';
|
||||
export { Badge } from './badge/badge';
|
||||
export { Ripple } from './ripple/ripple';
|
||||
export { Divider } from './divider/divider';
|
||||
export { Container } from './container/container';
|
||||
export { RippleArea } from './ripple/ripple-area';
|
||||
export { Ripples, Ripples } from './ripple/ripples';
|
||||
export { RippleEffect } from './ripple/ripple-effect';
|
||||
export { FAB } from './button-components/fab/fab';
|
||||
export { Radio } from './input-components/radio/radio';
|
||||
export { Switch } from './input-components/switch/switch';
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import { bool } from 'prop-types';
|
||||
import { CheckboxProps } from './checkbox.types';
|
||||
import { RippleArea } from '../../ripple/ripple-area';
|
||||
import { RippleEffect } from '../../ripple/ripple-effect';
|
||||
import useRippleEffect from '../../ripple/hooks/useRippleEffect';
|
||||
import { CheckBoxLayout } from '../checkbox-layout/check-box-layout';
|
||||
import {
|
||||
|
@ -45,7 +45,7 @@ export const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(
|
|||
/>
|
||||
<span className={'m3 m3-checkbox-state'} />
|
||||
<span className={'m3 m3-checkbox-state-layer'} />
|
||||
<RippleArea
|
||||
<RippleEffect
|
||||
callback={setIsActive}
|
||||
central={centralRipple}
|
||||
className={'m3-checkbox-ripple-layer'}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import { bool, string } from 'prop-types';
|
||||
import { RadioProps } from './radio.types';
|
||||
import { RippleArea } from '../../ripple/ripple-area';
|
||||
import { RippleEffect } from '../../ripple/ripple-effect';
|
||||
import { forwardRef, useRef, useState } from 'react';
|
||||
import useRippleEffect from '../../ripple/hooks/useRippleEffect';
|
||||
import { CheckBoxLayout } from '../checkbox-layout/check-box-layout';
|
||||
|
@ -37,7 +37,7 @@ export const Radio = forwardRef<HTMLInputElement, RadioProps>(
|
|||
cy={'50%'}
|
||||
/>
|
||||
</svg>
|
||||
<RippleArea
|
||||
<RippleEffect
|
||||
callback={setIsActive}
|
||||
central={centralRipple}
|
||||
className={'m3-checkbox-ripple-layer'}
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
import React, {
|
||||
ForwardedRef,
|
||||
MutableRefObject,
|
||||
useCallback,
|
||||
useImperativeHandle,
|
||||
useRef,
|
||||
useState,
|
||||
useTransition,
|
||||
} from 'react';
|
||||
import { Ripple } from '../ripple';
|
||||
import { baseDOMRect, RippleContainer } from '../ripple.types';
|
||||
import isEmpty, { rippleSizeCalculator } from '../utils/utils';
|
||||
import { InteractionEventsType } from './useRippleEffect';
|
||||
|
||||
const RIPPLE_LIFETIME: number = 550;
|
||||
const DEBOUNCE: number = 50;
|
||||
|
||||
const UseRippleBuilder = (
|
||||
stateRef: MutableRefObject<boolean>,
|
||||
rippleDomainRef: MutableRefObject<HTMLSpanElement>,
|
||||
central: boolean,
|
||||
forwardedRef: ForwardedRef<RippleContainer>,
|
||||
) => {
|
||||
const [ripples, setRipples] = useState({});
|
||||
const [pending, transition] = useTransition();
|
||||
const debounced = useRef<boolean>(false);
|
||||
const uniqueKey = useRef<number>(0);
|
||||
|
||||
const endLifetimeRipple = (keyRipple: number) => {
|
||||
if (!pending && !isEmpty(ripples)) {
|
||||
transition(() => {
|
||||
setRipples(prevRipples => {
|
||||
delete prevRipples[keyRipple];
|
||||
return prevRipples;
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const createRipple = useCallback(
|
||||
(
|
||||
event: InteractionEventsType,
|
||||
changeStateCallback: (state: boolean) => void,
|
||||
): void => {
|
||||
if (stateRef.current || debounced.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
debounced.current = true;
|
||||
|
||||
setTimeout(() => {
|
||||
debounced.current = false;
|
||||
}, DEBOUNCE);
|
||||
|
||||
stateRef.current = true;
|
||||
changeStateCallback(stateRef.current);
|
||||
|
||||
const rippleDomain: DOMRect | baseDOMRect = rippleDomainRef.current
|
||||
? rippleDomainRef.current.getBoundingClientRect()
|
||||
: {
|
||||
width: 0,
|
||||
height: 0,
|
||||
left: 0,
|
||||
top: 0,
|
||||
};
|
||||
|
||||
const [rippleX, rippleY, rippleS]: Array<number> =
|
||||
rippleSizeCalculator(event, rippleDomain, central);
|
||||
|
||||
const prevRipples = ripples;
|
||||
|
||||
prevRipples[uniqueKey.current] = (
|
||||
<Ripple
|
||||
endLifetime={endLifetimeRipple}
|
||||
key={uniqueKey.current}
|
||||
lifetime={RIPPLE_LIFETIME}
|
||||
rippleKey={uniqueKey.current}
|
||||
rippleS={rippleS}
|
||||
rippleX={rippleX}
|
||||
rippleY={rippleY}
|
||||
/>
|
||||
);
|
||||
|
||||
setRipples(prevRipples);
|
||||
|
||||
uniqueKey.current += 1;
|
||||
},
|
||||
[uniqueKey, debounced],
|
||||
);
|
||||
|
||||
const removeRipple = (
|
||||
event: InteractionEventsType,
|
||||
changeStateCallback: (state: boolean) => void,
|
||||
) => {
|
||||
if (!stateRef.current) {
|
||||
return;
|
||||
}
|
||||
stateRef.current = false;
|
||||
changeStateCallback(stateRef.current);
|
||||
};
|
||||
|
||||
useImperativeHandle(
|
||||
forwardedRef,
|
||||
() => ({
|
||||
start: createRipple,
|
||||
stop: removeRipple,
|
||||
current: rippleDomainRef,
|
||||
}),
|
||||
[createRipple, removeRipple],
|
||||
);
|
||||
|
||||
return ripples;
|
||||
};
|
||||
|
||||
export default UseRippleBuilder;
|
|
@ -1,131 +0,0 @@
|
|||
'use client';
|
||||
|
||||
import React, {
|
||||
forwardRef,
|
||||
ReactElement,
|
||||
useId,
|
||||
useImperativeHandle,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { Ripples, Ripple } from './ripples';
|
||||
import { RippleAreaProps } from './ripple.types';
|
||||
import { InteractionEventsType } from './hooks/useRippleEffect';
|
||||
|
||||
const TIMEOUT: number = 550;
|
||||
const rippleAreaContext = React.createContext(false);
|
||||
|
||||
const RippleArea = forwardRef(
|
||||
({ central = false, ...props }: RippleAreaProps, ref) => {
|
||||
const [ripples, setRipples] = useState<Array<ReactElement>>([]),
|
||||
rippleDomain = useRef(null),
|
||||
clicked = useRef<boolean>(false),
|
||||
uniqueKey = useRef<number>(0),
|
||||
uniqueId = useId();
|
||||
|
||||
const extraClassStyles =
|
||||
`m3 m3-ripple-domain ${props.className ?? ''}`.trimEnd();
|
||||
|
||||
const createRipple = (
|
||||
event: InteractionEventsType,
|
||||
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,
|
||||
};
|
||||
|
||||
const rippleX: number = !central
|
||||
? event.clientX - rippleDomainChar.left
|
||||
: rippleDomainChar.width / 2,
|
||||
rippleY: number = !central
|
||||
? event.clientY - rippleDomainChar.top
|
||||
: rippleDomainChar.height / 2,
|
||||
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<ReactElement>) => {
|
||||
if (prevRipples.length === 0) {
|
||||
return [
|
||||
<Ripple
|
||||
key={uniqueKey.current}
|
||||
lifetime={TIMEOUT}
|
||||
rippleS={rippleS}
|
||||
rippleX={rippleX}
|
||||
rippleY={rippleY}
|
||||
/>,
|
||||
];
|
||||
}
|
||||
const old = [...prevRipples];
|
||||
old.push(
|
||||
<Ripple
|
||||
key={uniqueKey.current}
|
||||
lifetime={TIMEOUT}
|
||||
rippleS={rippleS}
|
||||
rippleX={rippleX}
|
||||
rippleY={rippleY}
|
||||
/>,
|
||||
);
|
||||
return old;
|
||||
});
|
||||
|
||||
uniqueKey.current += 1;
|
||||
};
|
||||
|
||||
const removeRipple = (
|
||||
_event: InteractionEventsType,
|
||||
cb: (state: boolean) => void,
|
||||
) => {
|
||||
clicked.current = false;
|
||||
cb(clicked.current);
|
||||
|
||||
setRipples((prevRipples: Array<ReactElement>) => {
|
||||
if (prevRipples.length > 0) {
|
||||
const old = [...prevRipples];
|
||||
old.shift();
|
||||
return old;
|
||||
}
|
||||
return prevRipples;
|
||||
});
|
||||
};
|
||||
|
||||
useImperativeHandle(
|
||||
ref,
|
||||
() => ({
|
||||
start: createRipple,
|
||||
stop: removeRipple,
|
||||
}),
|
||||
[createRipple, removeRipple],
|
||||
);
|
||||
|
||||
return (
|
||||
<span className={extraClassStyles} id={uniqueId} ref={rippleDomain}>
|
||||
<rippleAreaContext.Provider value={clicked.current}>
|
||||
<Ripples>{ripples}</Ripples>
|
||||
</rippleAreaContext.Provider>
|
||||
</span>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
export { rippleAreaContext, RippleArea };
|
|
@ -0,0 +1,30 @@
|
|||
'use client';
|
||||
|
||||
import useRippleBuilder from './hooks/useRippleBuilder';
|
||||
import React, { forwardRef, useId, useRef } from 'react';
|
||||
import { RippleAreaProps, RippleContainer } from './ripple.types';
|
||||
|
||||
const rippleAreaContext = React.createContext(false);
|
||||
|
||||
const RippleEffect = forwardRef<RippleContainer, RippleAreaProps>(
|
||||
({ central = false, ...props }, ref) => {
|
||||
const uniqueId = useId(),
|
||||
rippleDomain = useRef<HTMLSpanElement>(null),
|
||||
clicked = useRef<boolean>(false),
|
||||
ripples = useRippleBuilder(clicked, rippleDomain, central, ref);
|
||||
|
||||
return (
|
||||
<span
|
||||
className={`m3 m3-ripple-domain ${props.className ?? ''}`.trimEnd()}
|
||||
id={uniqueId}
|
||||
ref={rippleDomain}
|
||||
>
|
||||
<rippleAreaContext.Provider value={clicked.current}>
|
||||
{Object.values(ripples)}
|
||||
</rippleAreaContext.Provider>
|
||||
</span>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
export { rippleAreaContext, RippleEffect };
|
|
@ -0,0 +1,38 @@
|
|||
'use client';
|
||||
|
||||
import { RippleProps } from './ripple.types';
|
||||
import { rippleAreaContext } from './ripple-effect';
|
||||
import React, { useContext, useLayoutEffect, useState } from 'react';
|
||||
|
||||
const Ripple = ({
|
||||
rippleX,
|
||||
rippleY,
|
||||
rippleS,
|
||||
lifetime,
|
||||
rippleKey,
|
||||
endLifetime,
|
||||
}: RippleProps) => {
|
||||
const [classes, setClasses] = useState<string>('m3 ripple visible');
|
||||
const rippleDomainContext = useContext(rippleAreaContext);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (endLifetime !== null && !rippleDomainContext) {
|
||||
setClasses('m3 ripple');
|
||||
setTimeout(() => endLifetime(rippleKey), lifetime);
|
||||
}
|
||||
}, [rippleDomainContext]);
|
||||
|
||||
return (
|
||||
<span
|
||||
className={classes}
|
||||
style={{
|
||||
left: -(rippleS / 2) + rippleX,
|
||||
top: -(rippleS / 2) + rippleY,
|
||||
width: rippleS,
|
||||
aspectRatio: 1,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export { Ripple };
|
|
@ -1,7 +1,28 @@
|
|||
import { Dispatch, HTMLAttributes, ReactElement, SetStateAction } from 'react';
|
||||
import {
|
||||
Dispatch,
|
||||
HTMLAttributes,
|
||||
MutableRefObject,
|
||||
SetStateAction,
|
||||
} from 'react';
|
||||
import { InteractionEventsType } from './hooks/useRippleEffect';
|
||||
|
||||
export interface RipplesProps extends HTMLAttributes<HTMLElement> {
|
||||
children?: ReactElement[];
|
||||
export type baseDOMRect = {
|
||||
width: number;
|
||||
height: number;
|
||||
left: number;
|
||||
top: number;
|
||||
};
|
||||
|
||||
export interface RippleContainer {
|
||||
start: (
|
||||
event: InteractionEventsType,
|
||||
changeStateCallback: (state: boolean) => void,
|
||||
) => void;
|
||||
stop: (
|
||||
event: InteractionEventsType,
|
||||
changeStateCallback: (state: boolean) => void,
|
||||
) => void;
|
||||
current: MutableRefObject<HTMLSpanElement>;
|
||||
}
|
||||
|
||||
export interface RipplePropsForComponents<T> extends HTMLAttributes<T> {
|
||||
|
@ -14,10 +35,10 @@ export interface RippleAreaProps extends HTMLAttributes<HTMLElement> {
|
|||
}
|
||||
|
||||
export interface RippleProps extends HTMLAttributes<HTMLElement> {
|
||||
rippleKey: number;
|
||||
rippleX: number;
|
||||
rippleY: number;
|
||||
rippleS: number;
|
||||
endLifetime?: () => void;
|
||||
lifetime: number;
|
||||
key?: number;
|
||||
endLifetime?: (value: number) => void;
|
||||
}
|
||||
|
|
|
@ -1,81 +0,0 @@
|
|||
'use client';
|
||||
|
||||
import isEmpty from './utils/utils';
|
||||
import { rippleAreaContext } from './ripple-area';
|
||||
import { RippleProps, RipplesProps } from './ripple.types';
|
||||
import RippleEffectBuild from './utils/ripple-effect-builder';
|
||||
import React, {
|
||||
ReactElement,
|
||||
useContext,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
useTransition,
|
||||
} from 'react';
|
||||
|
||||
const Ripples = (props: RipplesProps) => {
|
||||
const [ripples, setRipples] = useState({});
|
||||
const firstRender = useRef<boolean>(true);
|
||||
const [pending, startTransition] = useTransition();
|
||||
|
||||
const endLifetime = (child: ReactElement) => {
|
||||
if (child.props.endLifetime) {
|
||||
child.props.endLifetime();
|
||||
}
|
||||
|
||||
setRipples(state => {
|
||||
const children = { ...state };
|
||||
delete children[child.key];
|
||||
return children;
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (props.children.length > 0 && !pending) {
|
||||
startTransition(() => {
|
||||
if (firstRender.current || isEmpty(ripples)) {
|
||||
setRipples(RippleEffectBuild(props.children, endLifetime));
|
||||
firstRender.current = false;
|
||||
} else {
|
||||
setRipples(
|
||||
RippleEffectBuild(props.children, endLifetime, ripples),
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, [props.children]);
|
||||
|
||||
return <>{Object.values(ripples)}</>;
|
||||
};
|
||||
|
||||
const Ripple = ({
|
||||
rippleX,
|
||||
rippleY,
|
||||
rippleS,
|
||||
endLifetime,
|
||||
lifetime,
|
||||
}: RippleProps) => {
|
||||
const clicked = useContext<boolean>(rippleAreaContext);
|
||||
const [classes, setClasses] = useState<string>('m3 ripple visible');
|
||||
|
||||
useEffect(() => {
|
||||
if (endLifetime !== null && !clicked) {
|
||||
setClasses('m3 ripple');
|
||||
setTimeout(endLifetime, lifetime);
|
||||
}
|
||||
}, [clicked, endLifetime]);
|
||||
|
||||
return (
|
||||
<span
|
||||
className={classes}
|
||||
style={{
|
||||
left: -(rippleS / 2) + rippleX,
|
||||
top: -(rippleS / 2) + rippleY,
|
||||
width: rippleS,
|
||||
aspectRatio: 1,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export { Ripples, Ripple };
|
|
@ -1,15 +0,0 @@
|
|||
import { cloneElement, ReactElement } from 'react';
|
||||
|
||||
export default function ArrayConvertToObj(
|
||||
obj: object,
|
||||
nextChildren: ReactElement[],
|
||||
callback: (child: ReactElement) => void,
|
||||
): void {
|
||||
Object.values(nextChildren).forEach(
|
||||
(child: ReactElement) =>
|
||||
(obj[child.key] = cloneElement(child, {
|
||||
...child.props,
|
||||
endLifetime: callback.bind(null, child),
|
||||
})),
|
||||
);
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
import isEmpty from './utils';
|
||||
import ArrayConvertToObj from './array-convert-to-obj';
|
||||
import { cloneElement, ReactElement } from 'react';
|
||||
|
||||
export default function RippleEffectBuild(
|
||||
nextRipples: ReactElement[],
|
||||
callback: (child: ReactElement) => void,
|
||||
prevRipples?: object | null,
|
||||
) {
|
||||
const empty: boolean = isEmpty(prevRipples);
|
||||
const preparedRipples: object = empty ? {} : prevRipples;
|
||||
|
||||
switch (empty) {
|
||||
case true:
|
||||
ArrayConvertToObj(preparedRipples, nextRipples, callback);
|
||||
break;
|
||||
|
||||
case false:
|
||||
// eslint-disable-next-line no-case-declarations
|
||||
const next: object = {};
|
||||
ArrayConvertToObj(next, nextRipples, callback);
|
||||
for (const rippleKey of Object.keys(next)) {
|
||||
if (preparedRipples[rippleKey] == undefined) {
|
||||
preparedRipples[rippleKey] = cloneElement(next[rippleKey], {
|
||||
...next[rippleKey].props,
|
||||
endLifetime: callback.bind(null, next[rippleKey]),
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return preparedRipples;
|
||||
}
|
|
@ -1,6 +1,31 @@
|
|||
import { InteractionEventsType } from '../hooks/useRippleEffect';
|
||||
import { baseDOMRect } from '../ripple.types';
|
||||
|
||||
export default function isEmpty(obj: object): boolean {
|
||||
for (const _i in obj) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export function maxSize(size: number, cordPos: number): number {
|
||||
return Math.max(Math.abs(size - cordPos), cordPos);
|
||||
}
|
||||
|
||||
export function rippleSizeCalculator(
|
||||
event: InteractionEventsType,
|
||||
rippleDomain: DOMRect | baseDOMRect,
|
||||
centralRipple: boolean,
|
||||
): Array<number> {
|
||||
const rippleX: number = !centralRipple
|
||||
? event.clientX - rippleDomain.left
|
||||
: rippleDomain.width / 2,
|
||||
rippleY: number = !centralRipple
|
||||
? event.clientY - rippleDomain.top
|
||||
: rippleDomain.height / 2,
|
||||
rippleSizeX: number = maxSize(rippleDomain.width, rippleX) * 2,
|
||||
rippleSizeY: number = maxSize(rippleDomain.height, rippleY) * 2,
|
||||
rippleS: number = (rippleSizeX ** 2 + rippleSizeY ** 2) ** 0.5;
|
||||
|
||||
return [rippleX, rippleY, rippleS];
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue