@pmwcs/ripple
Version:
PMWCS ripple component
139 lines (128 loc) • 5.38 kB
JavaScript
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
};
};