All files / Validation Validation.tsx

100% Statements 16/16
100% Branches 7/7
100% Functions 2/2
100% Lines 15/15

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106              7x   7x           7x 7x 7x     7x 7x                             7x 24x 24x         24x                                                               7x 7x       7x                                           7x      
import _, { omit } from 'lodash';
import React from 'react';
import PropTypes from 'prop-types';
 
import { lucidClassNames } from '../../util/style-helpers';
import { getFirst, StandardProps } from '../../util/component-types';
 
const cx = lucidClassNames.bind('&-Validation');
 
const { string, any } = PropTypes;
 
/** Validation Error */
export interface IValidationErrorProps extends StandardProps {
	description?: string;
}
const ValidationError = (_props: IValidationErrorProps): null => null;
ValidationError.displayName = 'Validation.Error';
ValidationError.peek = {
	description: `Content that will be displayed as an error message.`,
};
ValidationError.propName = 'Error';
ValidationError.propTypes = {
	description: string,
	children: any,
};
 
/** Validation */
export interface IValidationProps
	extends StandardProps,
		React.DetailedHTMLProps<
			React.HTMLAttributes<HTMLDivElement>,
			HTMLDivElement
		> {
	Error?: React.ReactNode;
}
 
export const Validation = (props: IValidationProps): React.ReactElement => {
	const { className, children, ...passThroughs } = props;
	const errorChildProps = _.get(
		getFirst<IValidationErrorProps>(props, Validation.Error),
		'props'
	);
 
	return (
		<div
			{...omit(passThroughs, [
				'Error',
				'className',
				'children',
				'initialState',
				'callbackId',
			])}
			className={cx(
				'&',
				{
					'&-is-error': errorChildProps && errorChildProps.children,
				},
				className
			)}
		>
			{children}
			{errorChildProps &&
			errorChildProps.children &&
			errorChildProps.children !== true ? (
				<div
					{...omit(errorChildProps, ['initialState', 'callbackId'])}
					className={cx('&-error-content', errorChildProps.className)}
				>
					{errorChildProps.children}
				</div>
			) : null}
		</div>
	);
};
 
Validation.displayName = 'Validation';
Validation.peek = {
	description: `\`Validation\` is a wrapper component that's meant to be used by other components. Wrap your form components in one, and, if there's an error, style them accordingly.`,
	categories: ['helpers'],
};
Validation.propTypes = {
	/**
		In most cases this will be a string, but it also accepts any valid React
		element. If this is a falsey value, then no error message will be
		displayed.  If this is the literal \`true\`, it will add the
		\`-is-error\` class to the wrapper div, but not render the
		\`-error-content\` \`div\`.
	*/
	Error: any,
 
	/**
		Classes that are appended to the component defaults. This prop is run
		through the \`classnames\` library.
	*/
	className: string,
 
	/**
		Any valid React children.
	*/
	children: any.isRequired,
};
 
Validation.Error = ValidationError;
 
export default Validation;