UNPKG

@pmwcs/ripple

Version:

PMWCS ripple component

148 lines (130 loc) 4.51 kB
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } /* eslint react/no-find-dom-node: off */ import { h, Component, cloneElement, isValidElement, createContext } from 'preact'; import { findDOMNode, forwardRef, Children } from 'preact/compat'; import { classNames } from '@pmwcs/base'; import { useProviderContext } from '@pmwcs/provider'; import { useRippleFoundation } from './foundation'; const RippleSurfaceContext = createContext({}); /** A component for adding Ripples to other components. */ const withDomNode = () => WrapComponent => { return class extends Component { constructor() { super(); this.state = { domNode: null }; } componentDidMount() { this.setState({ domNode: findDOMNode(this) }); } componentDidUpdate() { const rootRippleElement = findDOMNode(this); if (rootRippleElement !== this.state.domNode) { this.setState({ rootRippleElement }); } } render() { return h(WrapComponent, _extends({}, this.props, { domNode: this.state.domNode })); } }; }; export const Ripple = withDomNode()(function Ripple(props) { const { children, className, primary, secondary, accent, unbounded, surface, domNode, foundationRef, ...rest } = props; const { rootEl, surfaceEl } = useRippleFoundation(props); const child = Children.only(children); if (!isValidElement(child)) { return null; } // This flag really determines a lot // is surfaceIsRoot is true, then the surface props are spread // to the underlying component, otherwise the only place they // can be picked up is by the context consumer const surfaceIsRoot = !surface || !unbounded; const unboundedProp = unbounded ? { 'data-mdc-ripple-is-unbounded': true } : {}; const rippleSurfaceProps = surfaceIsRoot ? surfaceEl.props({ style: child.props.style }) : {}; let finalClassNames = classNames(className !== child.props.className && className, rippleSurfaceProps.className, child.props.className, { 'mdc-ripple-surface': typeof surface === 'boolean' ? surface : surface === undefined, 'mdc-ripple-surface--primary': primary, 'mdc-ripple-surface--accent': accent || secondary }); // Fixes a ripple artifact issue // that is caused when clicking a button disables it // https://codesandbox.io/s/842vo56019 if (rest.disabled) { finalClassNames = finalClassNames.replace('mdc-ripple-upgraded--background-focused', ''); } // do some crazy props merging... const content = cloneElement(child, { ...child.props, ...unboundedProp, ...rootEl.props({ ...rest, style: child.props.style, ...rippleSurfaceProps, className: finalClassNames }) }); return h(RippleSurfaceContext.Provider, { value: surfaceEl.props({ style: child.props.style }) }, content); }); export const RippleSurface = ({ className, ...rest }) => h(RippleSurfaceContext.Consumer, null, rippleSurfaceProps => h("div", _extends({}, rest, rippleSurfaceProps, { className: `${className} ${rippleSurfaceProps.className || ''}` }))); /** * HOC that adds ripples to any component */ export const withRipple = ({ unbounded: defaultUnbounded, accent: defaultAccent, surface: defaultSurface }) => WrapComponent => { const WithRippleComponent = forwardRef(({ ripple, ...rest }, ref) => { var _ripple; const providerContext = useProviderContext(); ripple = (_ripple = ripple) !== null && _ripple !== void 0 ? _ripple : providerContext.ripple; const rippleOptions = typeof ripple !== 'object' ? {} : ripple; if (ripple) { return h(Ripple, _extends({}, rest, { accent: rippleOptions.accent || defaultAccent, unbounded: rippleOptions.unbounded || defaultUnbounded, surface: rippleOptions.surface || defaultSurface }), h(WrapComponent, _extends({}, rest, { ref: ref }))); } return h(WrapComponent, _extends({}, rest, { ref: ref })); }); WithRippleComponent.displayName = `withRipple(${WrapComponent.displayName || WrapComponent.constructor.name || 'Unknown'})`; return WithRippleComponent; };