UNPKG

@navinc/base-react-components

Version:
189 lines (162 loc) 4.92 kB
import React from 'react' import styled from 'styled-components' import Button from '../button' import Copy from '../copy' import Text from '../text' import Icon from '../icon.js' import NumberFormat from 'react-number-format' import CarrotDown from '../icons/actions/carrot-down' export const HelperIcon = styled(Icon)` max-width: 16px; max-height: 16px; fill: ${({ theme }) => theme.neutral400}; ` export const HelperDescription = styled(Copy).attrs(() => ({ size: 'sm', bold: true }))` color: inherit; ` export const HelperItem = styled.div.attrs( ({ isLink }) => isLink && { as: Button, variation: 'buttonLink', type: 'button' } )` display: grid; padding-top: 4px; grid-template-columns: min-content 1fr; grid-gap: 4px; text-align: left; ${({ hasSpaceForErrors }) => (hasSpaceForErrors ? 'min-height: 18px;' : '')} ${({ theme, isLink }) => !isLink && `color: ${theme.neutral400};`} ` export const Helper = styled(({ className, hasSpaceForHelper, helperLinkAction, helperText, iconName }) => ( <HelperItem className={className} isLink={!!helperLinkAction} onClick={helperLinkAction} hasSpaceForHelper={hasSpaceForHelper} > {iconName && <HelperIcon name={iconName} />} <HelperDescription data-testid={`input:helper-text:${helperText}`} light size="xs"> {helperText} </HelperDescription> </HelperItem> ))`` export const Label = styled(Text)` display: block; transition: all 0.2s linear; pointer-events: none; transform-origin: 0 0; &:focus { outline: none; } &::after { content: '${({ required }) => (required ? '*' : '')}'; } ` export const FieldWrapper = styled.div` display: grid; & > ${Copy} { margin-bottom: ${({ theme }) => theme.gu(1)}; } & * { font-family: inherit; } & > ${Label} { font-size: 14px; } & > ${Helper} { margin-left: ${({ theme }) => theme.gu(2)}; } ` FieldWrapper.displayName = 'FieldWrapper' export const Input = styled.input.withConfig({ shouldForwardProp: (prop) => !['isInvalid', 'hasSpaceForErrors'].includes(prop), })` width: 100%; border-width: 3px; border-style: solid; border-color: ${({ isInvalid, theme }) => (isInvalid ? theme.transparentRed : theme.bubbleBlue200)}; border-radius: 12px; font-weight: bold; background: ${({ isInvalid, theme }) => (isInvalid ? theme.sebastianRed100 : theme.bubbleBlue100)}; ${({ disabled, theme }) => disabled && `cursor: not-allowed; background: ${theme.scuttleGray100}`}; padding: ${({ theme }) => `${theme.gu(3)} ${theme.gu(2)} ${theme.gu(1)} ${theme.gu(2)}`}; &:focus, &:hover { outline: none; outline-offset: 0; } &:focus { border-color: ${({ theme }) => theme.bubbleBlue300}; } ` export const CurrencyInput = styled(Input).attrs(() => ({ as: NumberFormat, }))`` export const PercentInput = styled(Input).attrs(() => ({ as: NumberFormat }))`` export const NumberInput = styled(Input).attrs(() => ({ as: NumberFormat }))`` const ChevronWrapper = styled.div` pointer-events: none; & > ${Icon} { fill: ${({ isInvalid, disabled, theme }) => isInvalid ? theme.error : disabled ? theme.scuttleGray500 : theme.azure}; } ` export const Chevron = styled(({ className, disabled, isInvalid }) => ( <ChevronWrapper className={className} disabled={disabled} isInvalid={isInvalid}> <CarrotDown /> </ChevronWrapper> ))`` export const Field = styled.label` align-items: stretch; color: ${({ theme }) => theme.scuttleGray600}; cursor: pointer; display: flex; flex: 1 1 auto; margin-bottom: 0; overflow: hidden; position: relative; text-align: left; white-space: nowrap; & > * { width: 100%; border-radius: 12px; appearance: none; } & > ${Label} { will-change: transform; font-weight: ${({ isVisited }) => (isVisited ? 'normal' : 'bold')}; top: ${({ isVisited, theme }) => (isVisited ? theme.gu(1) : theme.gu(2))}; transform: ${({ isVisited }) => (isVisited ? 'scale(0.75)' : 'scale(1)')}; left: ${({ theme }) => theme.gu(2)}; position: absolute; transition: all 0.2s ease; color: ${({ theme }) => theme.scuttleGray600}; } * { font-size: 16px; } ${Input}:focus ~ ${Label}, &:hover ${Label}, &:active ${Label} { transform: scale(0.75); font-weight: normal; top: ${({ theme }) => theme.gu(1)}; } ${CurrencyInput}:focus + ${Label}, &:hover ${Label}, &:active ${Label} { color: ${({ theme }) => theme.scuttleGray600}; } & > ${Chevron} { width: min-content; position: absolute; right: 16px; top: 16px; } ` export const Err = styled(Copy).attrs(() => ({ size: 'sm', bold: true }))` color: ${({ theme }) => theme.error}; text-align: left; ` export const Errors = styled.div` ${({ hasSpaceForErrors }) => (hasSpaceForErrors ? 'min-height: 18px;' : '')} & > ${Err} { margin-left: ${({ theme }) => theme.gu(2)}; } `