@patreon/studio
Version:
Patreon Studio Design System
65 lines (62 loc) • 2.05 kB
JSX
import React, { Children, cloneElement } from 'react';
import { styled } from 'styled-components';
import { tokens } from '~/tokens';
/** Useful for when you want a group of `TextInput` and `Select` components to be rendered as one block.
* Visible labels should not be used on the middle or last children or it may lead to unexpected results.
*/
export const InputGroup = ({ children }) => {
// Filter out falsy and undefined values.
const filteredChildren = Array.isArray(children) ? children.filter((child) => !!child) : children;
const total = React.Children.count(filteredChildren);
return (<Container>
{Children.map(filteredChildren, (child, index) => {
// This is just to make typescript happpy as these values will already be filtered out above.
if (child) {
return (<InputWrapper hasError={!!child.props.error}>
{cloneElement(child, {
corners: getCorners({ index, isLast: index === total - 1 }),
width: 'fluid',
})}
</InputWrapper>);
}
return null;
})}
</Container>);
};
const Container = styled.div `
display: flex;
flex-direction: column;
width: 100%;
position: relative;
`;
const InputWrapper = styled.div `
z-index: ${({ hasError }) => (hasError ? 1 : 'auto')};
// Add negative margin for all children but the last to remove double borders
margin-bottom: calc(-1 * ${tokens.global.borderWidth.thin});
&:last-of-type {
margin-bottom: 0;
}
&:hover,
&:active,
&:focus,
&:focus-within {
z-index: 1;
}
`;
const getCorners = ({ index, isLast }) => {
// If there's just one child
if (index === 0 && isLast) {
return undefined;
}
// Element is on top
if (index === 0) {
return 'rounded-top';
}
// Element is on bottom
if (isLast) {
return 'rounded-bottom';
}
// Element is in the middle
return 'square';
};
//# sourceMappingURL=InputGroup.jsx.map