Spaces:
Sleeping
Sleeping
| 'use client'; | |
| import _extends from "@babel/runtime/helpers/esm/extends"; | |
| import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose"; | |
| const _excluded = ["center", "classes", "className"]; | |
| let _ = t => t, | |
| _t, | |
| _t2, | |
| _t3, | |
| _t4; | |
| import * as React from 'react'; | |
| import PropTypes from 'prop-types'; | |
| import { TransitionGroup } from 'react-transition-group'; | |
| import clsx from 'clsx'; | |
| import { keyframes } from '@mui/system'; | |
| import useTimeout from '@mui/utils/useTimeout'; | |
| import styled from '../styles/styled'; | |
| import { useDefaultProps } from '../DefaultPropsProvider'; | |
| import Ripple from './Ripple'; | |
| import touchRippleClasses from './touchRippleClasses'; | |
| import { jsx as _jsx } from "react/jsx-runtime"; | |
| const DURATION = 550; | |
| export const DELAY_RIPPLE = 80; | |
| const enterKeyframe = keyframes(_t || (_t = _` | |
| 0% { | |
| transform: scale(0); | |
| opacity: 0.1; | |
| } | |
| 100% { | |
| transform: scale(1); | |
| opacity: 0.3; | |
| } | |
| `)); | |
| const exitKeyframe = keyframes(_t2 || (_t2 = _` | |
| 0% { | |
| opacity: 1; | |
| } | |
| 100% { | |
| opacity: 0; | |
| } | |
| `)); | |
| const pulsateKeyframe = keyframes(_t3 || (_t3 = _` | |
| 0% { | |
| transform: scale(1); | |
| } | |
| 50% { | |
| transform: scale(0.92); | |
| } | |
| 100% { | |
| transform: scale(1); | |
| } | |
| `)); | |
| export const TouchRippleRoot = styled('span', { | |
| name: 'MuiTouchRipple', | |
| slot: 'Root' | |
| })({ | |
| overflow: 'hidden', | |
| pointerEvents: 'none', | |
| position: 'absolute', | |
| zIndex: 0, | |
| top: 0, | |
| right: 0, | |
| bottom: 0, | |
| left: 0, | |
| borderRadius: 'inherit' | |
| }); | |
| // This `styled()` function invokes keyframes. `styled-components` only supports keyframes | |
| // in string templates. Do not convert these styles in JS object as it will break. | |
| export const TouchRippleRipple = styled(Ripple, { | |
| name: 'MuiTouchRipple', | |
| slot: 'Ripple' | |
| })(_t4 || (_t4 = _` | |
| opacity: 0; | |
| position: absolute; | |
| &.${0} { | |
| opacity: 0.3; | |
| transform: scale(1); | |
| animation-name: ${0}; | |
| animation-duration: ${0}ms; | |
| animation-timing-function: ${0}; | |
| } | |
| &.${0} { | |
| animation-duration: ${0}ms; | |
| } | |
| & .${0} { | |
| opacity: 1; | |
| display: block; | |
| width: 100%; | |
| height: 100%; | |
| border-radius: 50%; | |
| background-color: currentColor; | |
| } | |
| & .${0} { | |
| opacity: 0; | |
| animation-name: ${0}; | |
| animation-duration: ${0}ms; | |
| animation-timing-function: ${0}; | |
| } | |
| & .${0} { | |
| position: absolute; | |
| /* @noflip */ | |
| left: 0px; | |
| top: 0; | |
| animation-name: ${0}; | |
| animation-duration: 2500ms; | |
| animation-timing-function: ${0}; | |
| animation-iteration-count: infinite; | |
| animation-delay: 200ms; | |
| } | |
| `), touchRippleClasses.rippleVisible, enterKeyframe, DURATION, ({ | |
| theme | |
| }) => theme.transitions.easing.easeInOut, touchRippleClasses.ripplePulsate, ({ | |
| theme | |
| }) => theme.transitions.duration.shorter, touchRippleClasses.child, touchRippleClasses.childLeaving, exitKeyframe, DURATION, ({ | |
| theme | |
| }) => theme.transitions.easing.easeInOut, touchRippleClasses.childPulsate, pulsateKeyframe, ({ | |
| theme | |
| }) => theme.transitions.easing.easeInOut); | |
| /** | |
| * @ignore - internal component. | |
| * | |
| * TODO v5: Make private | |
| */ | |
| const TouchRipple = /*#__PURE__*/React.forwardRef(function TouchRipple(inProps, ref) { | |
| const props = useDefaultProps({ | |
| props: inProps, | |
| name: 'MuiTouchRipple' | |
| }); | |
| const { | |
| center: centerProp = false, | |
| classes = {}, | |
| className | |
| } = props, | |
| other = _objectWithoutPropertiesLoose(props, _excluded); | |
| const [ripples, setRipples] = React.useState([]); | |
| const nextKey = React.useRef(0); | |
| const rippleCallback = React.useRef(null); | |
| React.useEffect(() => { | |
| if (rippleCallback.current) { | |
| rippleCallback.current(); | |
| rippleCallback.current = null; | |
| } | |
| }, [ripples]); | |
| // Used to filter out mouse emulated events on mobile. | |
| const ignoringMouseDown = React.useRef(false); | |
| // We use a timer in order to only show the ripples for touch "click" like events. | |
| // We don't want to display the ripple for touch scroll events. | |
| const startTimer = useTimeout(); | |
| // This is the hook called once the previous timeout is ready. | |
| const startTimerCommit = React.useRef(null); | |
| const container = React.useRef(null); | |
| const startCommit = React.useCallback(params => { | |
| const { | |
| pulsate, | |
| rippleX, | |
| rippleY, | |
| rippleSize, | |
| cb | |
| } = params; | |
| setRipples(oldRipples => [...oldRipples, /*#__PURE__*/_jsx(TouchRippleRipple, { | |
| classes: { | |
| ripple: clsx(classes.ripple, touchRippleClasses.ripple), | |
| rippleVisible: clsx(classes.rippleVisible, touchRippleClasses.rippleVisible), | |
| ripplePulsate: clsx(classes.ripplePulsate, touchRippleClasses.ripplePulsate), | |
| child: clsx(classes.child, touchRippleClasses.child), | |
| childLeaving: clsx(classes.childLeaving, touchRippleClasses.childLeaving), | |
| childPulsate: clsx(classes.childPulsate, touchRippleClasses.childPulsate) | |
| }, | |
| timeout: DURATION, | |
| pulsate: pulsate, | |
| rippleX: rippleX, | |
| rippleY: rippleY, | |
| rippleSize: rippleSize | |
| }, nextKey.current)]); | |
| nextKey.current += 1; | |
| rippleCallback.current = cb; | |
| }, [classes]); | |
| const start = React.useCallback((event = {}, options = {}, cb = () => {}) => { | |
| const { | |
| pulsate = false, | |
| center = centerProp || options.pulsate, | |
| fakeElement = false // For test purposes | |
| } = options; | |
| if ((event == null ? void 0 : event.type) === 'mousedown' && ignoringMouseDown.current) { | |
| ignoringMouseDown.current = false; | |
| return; | |
| } | |
| if ((event == null ? void 0 : event.type) === 'touchstart') { | |
| ignoringMouseDown.current = true; | |
| } | |
| const element = fakeElement ? null : container.current; | |
| const rect = element ? element.getBoundingClientRect() : { | |
| width: 0, | |
| height: 0, | |
| left: 0, | |
| top: 0 | |
| }; | |
| // Get the size of the ripple | |
| let rippleX; | |
| let rippleY; | |
| let rippleSize; | |
| if (center || event === undefined || event.clientX === 0 && event.clientY === 0 || !event.clientX && !event.touches) { | |
| rippleX = Math.round(rect.width / 2); | |
| rippleY = Math.round(rect.height / 2); | |
| } else { | |
| const { | |
| clientX, | |
| clientY | |
| } = event.touches && event.touches.length > 0 ? event.touches[0] : event; | |
| rippleX = Math.round(clientX - rect.left); | |
| rippleY = Math.round(clientY - rect.top); | |
| } | |
| if (center) { | |
| rippleSize = Math.sqrt((2 * rect.width ** 2 + rect.height ** 2) / 3); | |
| // For some reason the animation is broken on Mobile Chrome if the size is even. | |
| if (rippleSize % 2 === 0) { | |
| rippleSize += 1; | |
| } | |
| } else { | |
| const sizeX = Math.max(Math.abs((element ? element.clientWidth : 0) - rippleX), rippleX) * 2 + 2; | |
| const sizeY = Math.max(Math.abs((element ? element.clientHeight : 0) - rippleY), rippleY) * 2 + 2; | |
| rippleSize = Math.sqrt(sizeX ** 2 + sizeY ** 2); | |
| } | |
| // Touche devices | |
| if (event != null && event.touches) { | |
| // check that this isn't another touchstart due to multitouch | |
| // otherwise we will only clear a single timer when unmounting while two | |
| // are running | |
| if (startTimerCommit.current === null) { | |
| // Prepare the ripple effect. | |
| startTimerCommit.current = () => { | |
| startCommit({ | |
| pulsate, | |
| rippleX, | |
| rippleY, | |
| rippleSize, | |
| cb | |
| }); | |
| }; | |
| // Delay the execution of the ripple effect. | |
| // We have to make a tradeoff with this delay value. | |
| startTimer.start(DELAY_RIPPLE, () => { | |
| if (startTimerCommit.current) { | |
| startTimerCommit.current(); | |
| startTimerCommit.current = null; | |
| } | |
| }); | |
| } | |
| } else { | |
| startCommit({ | |
| pulsate, | |
| rippleX, | |
| rippleY, | |
| rippleSize, | |
| cb | |
| }); | |
| } | |
| }, [centerProp, startCommit, startTimer]); | |
| const pulsate = React.useCallback(() => { | |
| start({}, { | |
| pulsate: true | |
| }); | |
| }, [start]); | |
| const stop = React.useCallback((event, cb) => { | |
| startTimer.clear(); | |
| // The touch interaction occurs too quickly. | |
| // We still want to show ripple effect. | |
| if ((event == null ? void 0 : event.type) === 'touchend' && startTimerCommit.current) { | |
| startTimerCommit.current(); | |
| startTimerCommit.current = null; | |
| startTimer.start(0, () => { | |
| stop(event, cb); | |
| }); | |
| return; | |
| } | |
| startTimerCommit.current = null; | |
| setRipples(oldRipples => { | |
| if (oldRipples.length > 0) { | |
| return oldRipples.slice(1); | |
| } | |
| return oldRipples; | |
| }); | |
| rippleCallback.current = cb; | |
| }, [startTimer]); | |
| React.useImperativeHandle(ref, () => ({ | |
| pulsate, | |
| start, | |
| stop | |
| }), [pulsate, start, stop]); | |
| return /*#__PURE__*/_jsx(TouchRippleRoot, _extends({ | |
| className: clsx(touchRippleClasses.root, classes.root, className), | |
| ref: container | |
| }, other, { | |
| children: /*#__PURE__*/_jsx(TransitionGroup, { | |
| component: null, | |
| exit: true, | |
| children: ripples | |
| }) | |
| })); | |
| }); | |
| process.env.NODE_ENV !== "production" ? TouchRipple.propTypes = { | |
| /** | |
| * If `true`, the ripple starts at the center of the component | |
| * rather than at the point of interaction. | |
| */ | |
| center: PropTypes.bool, | |
| /** | |
| * Override or extend the styles applied to the component. | |
| */ | |
| classes: PropTypes.object, | |
| /** | |
| * @ignore | |
| */ | |
| className: PropTypes.string | |
| } : void 0; | |
| export default TouchRipple; |