iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 20
1
自我挑戰組

30 天來點 Design System系列 第 20

Day 20 建立 文字 與 Message

  • 分享至 

  • xImage
  •  

建立文字級距與提示彈窗

Typography

import React from 'react';
import styled from 'styled-jss';
import propTypes from 'prop-types';

const StyledTypography = styled('p')(({ theme, style, variant = 'content' }) => ({
  margin: 0,
  color: theme.colors.black,
  ...theme.typography[variant],
  ...style
}));

const Typography = ({ type, children, ...props }) => {
  return <StyledTypography {...props}>{children}</StyledTypography>
}

Typography.propTypes = {
  style: propTypes.object,
  variant: propTypes.oneOf(['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'content']),
}

Typography.defaultProps = {
  style: {},
  variant: 'content',
}

export default Typography;

Usage

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

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

const Template = (args) => {
  return (
    <Provider>
      <Fragment>
        <Typography variant='h1'>H1 Typography</Typography>
        <Typography variant='h2'>H2 Typography</Typography>
        <Typography variant='h3'>H3 Typography</Typography>
        <Typography variant='h4'>H4 Typography</Typography>
        <Typography variant='h5'>H5 Typography</Typography>
        <Typography variant='h6'>H6 Typography</Typography>
        <Typography variant='content'>content</Typography>
      </Fragment>
    </Provider>
  );
};

export const Default = Template.bind({});

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

結果如下:

Message

import React from "react";
import styled from "styled-jss";
import propTypes from "prop-types";
import Icon from "../Icon";
import Typography from "../Typography";
import { useEffect } from 'react';

const ICON_MAP = {
  info: "fa-info-circle",
  success: "fa-check-circle",
  warning: "fa-exclamation-circle",
  danger: "fa-exclamation-triangle",
};

const getIconColor = (theme) => ({
  info: theme.colors.info,
  success: theme.colors.success,
  danger: theme.colors.danger,
  warning: theme.colors.warning,
});

const StyledIcon = styled(Icon)(({ theme, type }) => ({
  marginRight: theme.getSpacing(1),
  color: getIconColor(theme)[type],
}));

const StyledMessageContainer = styled("div")({
  justifyContent: "center",
  position: "fixed",
  display: "flex",
  width: "100vw",
  left: 0,
  top: 0,
});

const activeStyle = (active) => {
  console.log("TCL: activeStyle -> active", active)
  return active ? { 
    top: 20,
    opacity: 1
  }: {};
}

const StyledMessage = styled("span")(({ theme, active }) => ({
  top: 0,
  opacity:0,
  zIndex: 1000,
  minWidth: 300,
  margin: "auto",
  display: "flex",
  position: "fixed",
  alignItems: "center",
  transition: 'all .3s ease',
  justifyContent: "flex-star",
  boxShadow: "0px 2px 3px rgba(0, 0, 0, 0.17)",
  borderRadius: theme.radius,
  backgroundColor: theme.colors.white,
  border: `1px solid ${theme.colors.grey1}`,
  padding: `${theme.getSpacing(1)}px ${theme.getSpacing(2)}px`,
  ...activeStyle(active),
 
}));

const Message = ({ open, type, content, onClose, duration, ...props }) => {

  useEffect(() => {
    if(open) {
      setTimeout(() => {
        onClose();
      },duration);
    }
  }, [open])

  return (
    <StyledMessageContainer>
      <StyledMessage {...props} active={open} >
        <StyledIcon type={type} icon={ICON_MAP[type]} />
        <Typography>{content}</Typography>
      </StyledMessage>
    </StyledMessageContainer>
  );
};

Message.propTypes = {
  open: propTypes.bool,
  content: propTypes.string,
  duration: propTypes.number,
  type: propTypes.oneOf(["info", "success", "danger", "warning"]),
};

Message.defaultProps = {
  open: false,
  content: "",
  type: "info",
  duration: 2500,
};

export default Message;

Usage

import React, { Fragment, useState } from "react";
import theme from "../../lib/theme";
import Button from "../../lib/Button";
import Message from "../../lib/Message";
import ThemeProvider from "../../lib/ThemeProvider";

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

const Template = args => {

    const [open, setOpen] = useState(false);

    return (
        <Provider>
            <Fragment>
                <Message
                  open={open}
                  content='提示信息'
                  onClose={() => setOpen(false)}>
                    顯示信息彈窗的內容..
                </Message>
                <Button onClick={() => setOpen(true)}>Show Message</Button>
            </Fragment>
        </Provider>
    );
}

export const Default = Template.bind({});

export default {
    component: Message,
    title: "Feedback/Message",
};

結果如下:


上一篇
Day 19 建立 Dialog
下一篇
Day 21 建立 MenuItem
系列文
30 天來點 Design System30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言