Source

adminjs-design-system/src/atoms/input.tsx

import styled, { css } from 'styled-components'
import { rgba } from 'polished'
import { space, SpaceProps, layout, LayoutProps, variant } from 'styled-system'
import focusShadowStyle from '../utils/focus-shadow.style'
import { cssClass } from '../utils/css-class'

const borderlessCSS = css`
  padding: 0;
  border-color: transparent;
  border-width: 0 0 1px 0;
  color: ${({ theme }) => theme.colors.grey100};
  &:focus {
    box-shadow: none;
    border-bottom: 1px solid ${({ theme }): string => theme.colors.inputBorder};
  }

  &:hover {
    cursor: pointer;
  }
`

const sizeVariants = variant({
  prop: 'variant',
  variants: {
    default: {
      fontSize: 'default',
      lineHeight: 'lg',
    },
    sm: {
      fontSize: 'sm',
      lineHeight: 'default',
    },
    lg: {
      fontSize: 'lg',
      lineHeight: 'xl',
    },
    xl: {
      fontSize: 'xl',
      lineHeight: 'xxl',
    },
    xxl: {
      fontSize: 'h1',
      fontWeight: 'light',
      lineHeight: 'x4',
    },
  },
})

/**
 * Input CSS Styles which can be reused in another input component with styled-components
 *
 * ### Usage:
 *
 * ```
 * import { InputCSS } from '@adminjs/design-system'
 *
 * const MyStyledInput = styled.input`
 *   ${InputCSS}
 * `
 * ```
 * @memberof Input
 * @alias InputCSS
 */
export const InputCSS = css<InputProps>`
  box-sizing: border-box;
  color: ${({ theme }): string => theme.colors.grey80};
  background: transparent;
  border: 1px solid ${({ theme }): string => theme.colors.inputBorder};
  font-size: ${({ theme }): string => theme.fontSizes.default};
  line-height: ${({ theme }): string => theme.lineHeights.lg};
  font-family: ${({ theme }): string => theme.font};
  outline: none;
  &:hover {
    border-color: ${({ theme }): string => theme.colors.grey60};
  }
  &:focus {
    border-color: ${({ theme }): string => theme.colors.primary100};
    ${({ theme }): string => `box-shadow: ${focusShadowStyle(theme)}`};
  }
  &:disabled {
    color: ${({ theme }): string => rgba(theme.colors.grey80, 0.5)};
    border-color: ${({ theme }): string => rgba(theme.colors.inputBorder, 0.5)};
  }

  ${({ borderless }): any => (borderless ? borderlessCSS : '')};
  ${sizeVariants};
`

/**
 * Prop Types of an Input component.
 * Apart from variant it extends all {@link LayoutProps} and {@link SpaceProps}
 *
 * @memberof Input
 * @alias InputProps
 * @property {string} [...] Other props from {@link LayoutProps}, {@link SpaceProps}
 */
export type InputProps = SpaceProps & LayoutProps & {
  borderless?: boolean;
  variant?: 'sm' | 'lg' | 'xl' | 'default' | 'xxl';
}

/**
 * @classdesc
 *
 * <img src="components/input.png" />
 *
 * Wrapped `input` html element.
 *
 * ### Usage
 *
 * ```javascript
 * import { Input, InputProps, InputCSS } from '@adminjs/design-system'
 * ```
 *
 * @component
 * @subcategory Atoms
 * @see InputProps
 * @see {@link https://storybook.adminjs.co/?path=/story/designsystem-atoms-input--default Storybook}
 * @hideconstructor
 * @example
 * return (
 *   <Box p="xl">
 *      <Label htmlFor="input1">Some example label</Label>
 *      <Input id="input1" width={1/2} />
 *   </Box>
 * )
 * @section design-system
 */
const Input = styled.input<InputProps>`
  ${InputCSS};
  ${space};
  ${layout};
`

Input.defaultProps = {
  px: 'default',
  py: 'sm',
  className: cssClass('Input'),
}

export { Input }
export default Input