UNPKG

@pmwcs/ripple

Version:

PMWCS ripple component

139 lines (128 loc) 5.38 kB
import { useCallback, useRef, useEffect } from 'preact/hooks'; import { useFoundation, emptyClientRect, matches, applyPassive } from '@pmwcs/base'; import { MDCRippleFoundation, util } from '@material/ripple'; export const useRippleFoundation = props => { const isTouched = useRef(false); const { foundation, ...elements } = useFoundation({ props, elements: { rootEl: true, surfaceEl: true }, foundation: ({ rootEl, surfaceEl, getProps }) => { return new MDCRippleFoundation({ browserSupportsCssVars: () => util.supportsCssVariables(window), isUnbounded: () => !!getProps().unbounded, isSurfaceActive: () => { if (rootEl.ref) { return matches(rootEl.ref, ':active'); } return false; }, isSurfaceDisabled: () => !!getProps().disabled, addClass: className => { surfaceEl.addClass(className); }, removeClass: className => { surfaceEl.removeClass(className); }, containsEventTarget: target => !!rootEl.ref && rootEl.ref.contains(target), registerInteractionHandler: () => {}, deregisterInteractionHandler: () => {}, registerDocumentInteractionHandler: (evtType, handler) => document.documentElement.addEventListener(evtType, handler, applyPassive()), deregisterDocumentInteractionHandler: (evtType, handler) => document.documentElement.removeEventListener(evtType, handler, applyPassive()), registerResizeHandler: handler => window.addEventListener('resize', handler), deregisterResizeHandler: handler => window.removeEventListener('resize', handler), updateCssVariable: (varName, value) => surfaceEl.setStyle(varName, value), computeBoundingRect: () => rootEl.ref ? rootEl.ref.getBoundingClientRect() : emptyClientRect, getWindowPageOffset: () => ({ x: window.pageXOffset, y: window.pageYOffset }) }); } }); const { rootEl } = elements; const activateRipple = useCallback(evt => { // https://reactjs.org/docs/events.html#event-pooling evt.persist(); foundation.activate(evt); }, [foundation]); const deactivateRipple = useCallback(evt => { // https://reactjs.org/docs/events.html#event-pooling evt.persist(); foundation.deactivate(); }, [foundation]); const handleFocus = useCallback(evt => { var _props$onFocus; (_props$onFocus = props.onFocus) === null || _props$onFocus === void 0 ? void 0 : _props$onFocus.call(props, evt); foundation.handleFocus(); }, [foundation, props.onFocus]); const handleBlur = useCallback(evt => { var _props$onBlur; (_props$onBlur = props.onBlur) === null || _props$onBlur === void 0 ? void 0 : _props$onBlur.call(props, evt); foundation.handleBlur(); }, [foundation, props.onBlur]); const handleMouseDown = useCallback(evt => { var _props$onMouseDown; (_props$onMouseDown = props.onMouseDown) === null || _props$onMouseDown === void 0 ? void 0 : _props$onMouseDown.call(props, evt); if (!isTouched.current) { activateRipple(evt); } isTouched.current = false; }, [props.onMouseDown, activateRipple]); const handleMouseUp = useCallback(evt => { var _props$onMouseUp; (_props$onMouseUp = props.onMouseUp) === null || _props$onMouseUp === void 0 ? void 0 : _props$onMouseUp.call(props, evt); deactivateRipple(evt); }, [props.onMouseUp, deactivateRipple]); const handleTouchStart = useCallback(evt => { var _props$onTouchStart; isTouched.current = true; (_props$onTouchStart = props.onTouchStart) === null || _props$onTouchStart === void 0 ? void 0 : _props$onTouchStart.call(props, evt); activateRipple(evt); }, [props.onTouchStart, activateRipple]); const handleTouchEnd = useCallback(evt => { var _props$onTouchEnd; (_props$onTouchEnd = props.onTouchEnd) === null || _props$onTouchEnd === void 0 ? void 0 : _props$onTouchEnd.call(props, evt); deactivateRipple(evt); }, [props.onTouchEnd, deactivateRipple]); const handleKeyDown = useCallback(evt => { var _props$onKeyDown; (_props$onKeyDown = props.onKeyDown) === null || _props$onKeyDown === void 0 ? void 0 : _props$onKeyDown.call(props, evt); activateRipple(evt); }, [props.onKeyDown, activateRipple]); const handleKeyUp = useCallback(evt => { var _props$onKeyUp; (_props$onKeyUp = props.onKeyUp) === null || _props$onKeyUp === void 0 ? void 0 : _props$onKeyUp.call(props, evt); deactivateRipple(evt); }, [props.onKeyUp, deactivateRipple]); rootEl.setProp('onFocus', handleFocus, true); rootEl.setProp('onBlur', handleBlur, true); rootEl.setProp('onMouseDown', handleMouseDown, true); rootEl.setProp('onMouseUp', handleMouseUp, true); rootEl.setProp('onTouchStart', handleTouchStart, true); rootEl.setProp('onTouchEnd', handleTouchEnd, true); rootEl.setProp('onKeyDown', handleKeyDown, true); rootEl.setProp('onKeyUp', handleKeyUp, true); useEffect(() => { rootEl.setRef(props.domNode); }, [rootEl, props.domNode]); useEffect(() => { foundation.setUnbounded(!!props.unbounded); }, [props.unbounded, foundation]); useEffect(() => { props.disabled && foundation.handleBlur(); }, [props.disabled, foundation]); return { ...elements }; };