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