iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 23
1

Input 的部分包含 label 以及 輸入匡本體

  • value 輸入值
  • reqired 是否為必填
  • disabled 禁止輸入
  • errorMessage 錯誤信息

Input

import React, { Fragment } from "react";
import styled from "styled-jss";
import propTypes from "prop-types";
import isEmpty from 'lodash/isEmpty';
import breakpoint from "../constant/breakpoint";

const StyledLabel = styled("label")({
  minWidth: 80,
  position: "relative",
  color: ({ theme }) => theme.colors.grey4,
  padding: ({ theme }) => `${theme.getSpacing(1)}px ${theme.getSpacing(1)}px`,
  "&::after": {
    position: "absolute",
    content: ({ required }) => (required ? '"*"' : '""'),
    color: ({ theme }) => theme.colors.danger,
    marginLeft: 2,
  },
  [breakpoint.mediaLG]: {
    padding: ({ theme }) => `${theme.getSpacing(1)}px ${theme.getSpacing(2)}px`,
    "&::after": {
      left: 2,
    },
  },
});

const StyledInput = styled("input")({
  flex: 1,
  outline: "none",
  borderRadius: ({ theme }) => theme.radius,
  fontSize: ({ theme }) => theme.typography.content.fontSize,
  padding: ({ theme }) => `${theme.getSpacing(1)}px ${theme.getSpacing(2)}px`,
  border: ({ theme, errorMessage }) => `1px solid ${ isEmpty(errorMessage) ? theme.colors.grey1: theme.colors.danger}`,
  "&:active, &:focus": {
    border: ({ theme }) => `1px solid ${theme.colors.primary}`,
  },
  color: ({ theme, disabled }) => disabled ? theme.colors.grey2: theme.colors.black,
  backgroundColor: ({ theme, disabled }) => disabled ? theme.colors.grey0: theme.colors.white,
});

const StyledFormGroup = styled("div")({
  display: "flex",
  flexDirection: "column",
  justifyContent: "flex-star",
  [breakpoint.mediaLG]: {
    display: "flex",
    alignItems: "center",
    flexDirection: "row",
    boxSizing: "border-box",
    justifyContent: "center",
  },
});

const StyedErrorMessage = styled("div")({
  color: ({ theme }) => theme.colors.danger,
  paddingLeft: ({ theme }) => theme.getSpacing(1),
  [breakpoint.mediaLG]: {
    paddingLeft: ({ theme }) => theme.getSpacing(15),
  },
});

const Input = ({
  label,
  value,
  required,
  onChange,
  errorMessage,
  ...props
}) => {
  return (
    <Fragment>
      <StyledFormGroup>
        <StyledLabel required={required}>{label}</StyledLabel>
        <StyledInput value={value} onChange={onChange} errorMessage={errorMessage} {...props} />
      </StyledFormGroup>
      <StyedErrorMessage errorMessage={errorMessage}>
        {errorMessage}
      </StyedErrorMessage>
    </Fragment>
  );
};

Input.propTypes = {
  label: propTypes.string,
  onChange: propTypes.func,
  required: propTypes.bool,
  errorMessage: propTypes.string,
  value: propTypes.oneOfType([
    propTypes.string,
    propTypes.number,
    propTypes.instanceOf(Date),
  ]),
};

Input.defaultProps = {
  label: "",
  value: "",
  required: false,
  errorMessage: "",
  onChange: () => false,
};

export default Input;

Usage

import React, { Fragment } from "react";
import theme from "../../lib/theme";
import Input from "../../lib/Input";
import FormControl from "../../lib/FormControl";
import ThemeProvider from "../../lib/ThemeProvider";

const Provider = (props) => {
  return <ThemeProvider theme={theme}>{props.children}</ThemeProvider>;
};

const Template = (args) => {
  return (
    <Provider>
      <Fragment>
        <Input {...args} />
      </Fragment>
    </Provider>
  );
};

const TemplateForm = (args) => {
  return (
    <Provider>
      <Fragment>
        <FormControl>
            <Input type='text' label="username" placeholder='username' />
        </FormControl>
        <FormControl>
            <Input disabled type='text' label="disabled" value='disabled' />
        </FormControl>
        <FormControl>
          <Input required type='text' label="account" placeholder='account' />
        </FormControl>
        <FormControl>
          <Input required type='text' label="phone" placeholder='phone' errorMessage='error message' />
        </FormControl>
      </Fragment>
    </Provider>
  );
};

export const TextInput = TemplateForm.bind({});
TextInput.args = {
  type: 'text',
  label: 'UserName',
  placeholder: 'Please input username'
}

export default {
  component: Input,
  title: "Components/Input",
};

結果如下:

Reference

58 Form Design Best Practices & Form UX Examples


上一篇
Day 22 建立 Alert
下一篇
Day 24 建立 Radio & Checkbox
系列文
30 天來點 Design System30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言