Home Reference Source Repository

src/ActionSheet/index.js

import React, {
  Component,
  PropTypes
} from 'react';
import './style';
import {classNames, createInstance} from '../utils';
import Popup from '../Popup';

let apiInstance;


/**
 * action 按钮
 * @param {object} props see Button.propTypes
 */
function Button(props) {
  const {index, children, cancel, destroy, callback} = props;
  let className = classNames('action-sheet-item', {
    'action-sheet-item-cancel': cancel,
    'action-sheet-item-destroy': destroy
  });

  return (
    <li className={className} onClick={() => callback(index)}>
      <button>{children}</button>
    </li>
  );
}

/**
 * 传入 Button 的属性
 * @type {Object}
 * index: 索引
 * children: 按钮(button)内容
 * cancel: 是取消按钮?
 * destroy: 是销毁按钮?
 * callback: 点击 action 按钮的回调,参数为对应的 action 索引
 */
Button.propTypes = {
  index: PropTypes.number.isRequired,
  children: PropTypes.node.isRequired,
  cancel: PropTypes.bool,
  destroy: PropTypes.bool,
  callback: PropTypes.func.isRequired
};

/**
 * ActionSheet UI
 * @param {object} props see ActionSheet.propTypes
 */
export default function ActionSheet(props) {
  let {
    title,
    actions,
    callback,
    cancelIndex,
    destroyIndex,
    className,
    ...others
  } = props;
  className = classNames('action-sheet', {_user: className});
  typeof cancelIndex === 'undefined' && (cancelIndex = actions.length - 1);


  return (
    <div className={className} {...others}>
      {title ? (<header>{title}</header>) : null}
      <ol>{actions.map((content, index) => {
        return (
          <Button
            key={index}
            index={index}
            cancel={cancelIndex === index}
            destroy={destroyIndex === index}
            callback={callback}>
            {content}
          </Button>
        );
      })}</ol>
    </div>
  );
}

/**
 * ActionSheet 的 props
 * @type {Object}
 * title: 标题
 * actions: 多个动作 action[0] === PropTypes.node
 * callback: 点击动作后的回调
 * cancelIndex: “取消动作”的索引
 * destroyIndex: “销毁动作”的索引
 */
ActionSheet.propTypes = {
  title: PropTypes.node,
  actions: PropTypes.array.isRequired,
  callback: PropTypes.func.isRequired,
  cancelIndex: PropTypes.number,
  destroyIndex: PropTypes.number,
  className: PropTypes.string
};

/**
 * 创建 ActionSheet 的 ApiContainer 实例
 * @param  {node} container {@see createInstance}
 * @return {PropTypes.element}           React elment 对象
 */
ActionSheet.getInstance = (container) => {
  return createInstance(ApiContainer, container);
};

/**
 * 显示全局ActionSheet
 * @param  {object} props      see ActionSheet.propTypes
 * @param  {object} popupProps {@see Popup}
 * @return {[type]}            [description]
 */
ActionSheet.show = (props, popupProps) => {
  apiInstance.show(props, popupProps);
};





class ApiContainer extends Component {
  state = {
    props: {
      actions: [],
      callback: () => {}
    },
    popupProps: {
      show: false
    }
  };

  render() {
    let {props, popupProps} = this.state;

    return (
      <Popup {...popupProps}>
        <ActionSheet {...props} />
      </Popup>
    );
  }

  show(props, popupProps) {
    props = this._decorateProps(props);

    let nextState = {
      props: {...this.state.props, ...props},
      popupProps: {...this.state.popupProps, ...popupProps, show: true}
    };

    this.setState(nextState);
  }

  hide() {
    let nextState = {
      ...this.state,
      popupProps: {...this.state.popupProps, show: false}
    };

    this.setState(nextState);
  }

  _decorateProps(props) {
    let callback = props.callback;
    props.callback = (index) => {
      callback && callback(index);
      this.hide();
    };

    return props;
  }
}


apiInstance = createInstance(ApiContainer);