diff --git a/README.md b/README.md index 06eb91e6..18093210 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ const App = () => { ### Action Components -- [ ] ActionSheet +- [x] ActionSheet - [ ] Dialog - [ ] DropdownMenu - [ ] Loading diff --git a/src/components/ActionSheet/ActionSheet.tsx b/src/components/ActionSheet/ActionSheet.tsx new file mode 100644 index 00000000..ac3faf69 --- /dev/null +++ b/src/components/ActionSheet/ActionSheet.tsx @@ -0,0 +1,135 @@ +/* + * @Author: zhaohui + * @Date: 2021-05-29 12:11:37 + * @LastEditTime: 2021-05-30 15:45:07 + * @LastEditors: zhaohui + * @Description: + * @FilePath: /vant-react/src/components/ActionSheet/ActionSheet.tsx + */ +import React from 'react'; +import { ActionSheetProps, ActionItem, BaseClass } from './types'; +import classnames from '../../utils/classNames'; +import { renderLoadingIcon } from '../Button/helper'; +import Icon from '../Icons'; +import './index.scss'; + +const ActionSheet = ({ + actions, + cancelText, + description, + cancelClick, + closeIcon, + closeable, + title +}: ActionSheetProps) => { + const containerStyle = { + className: classnames(`${BaseClass}__container`, []), + style: {} + }; + const actionCon = { + className: classnames(`${BaseClass}__action__con`, []), + style: {} + }; + const actionDescription = { + className: classnames(`${BaseClass}__description`, []), + style: {} + }; + const actionItem = { + className: classnames(`${BaseClass}__action__item`, []), + style: {} + }; + const actionItemSubName = { + className: classnames(`${BaseClass}__action__item__subName`, []), + style: {} + }; + const _closeIcon = { + className: classnames(`${BaseClass}__close`, []), + style: {} + }; + const _titleStyle = { + className: classnames(`${BaseClass}__title`, []), + style: {} + }; + return ( +
+ {closeable && ( +
cancelClick && cancelClick() + })} + > + {typeof closeIcon === 'string' ? ( + + ) : ( + + )} +
+ )} + +
+ {title && typeof title === 'string' ? ( +
{title}
+ ) : ( + title + )} + {description && typeof description === 'string' ? ( +
{description}
+ ) : ( + description + )} + {actions && + actions.map((item: ActionItem) => ( + + ))} + {cancelText &&
} + {cancelText && typeof cancelText === 'string' ? ( + + ) : ( + cancelText + )} +
+
+ ); +}; +export default ActionSheet; diff --git a/src/components/ActionSheet/index.scss b/src/components/ActionSheet/index.scss new file mode 100644 index 00000000..3dbf5f19 --- /dev/null +++ b/src/components/ActionSheet/index.scss @@ -0,0 +1,80 @@ +@import '../../styles/colors.scss'; + +$baseClass: 'vant-action-sheet'; + +* { + box-sizing: border-box; +} +.#{$baseClass}__gap { + height: 8px; + background: $grey-background; +} +.#{$baseClass}__close { + position: absolute; + top: 5px; + right: 5px; + color: $placeholder; + font-size: 22px; + cursor: pointer; +} +.#{$baseClass}__title { + flex-shrink: 0; + font-weight: 500; + font-size: 16px; + line-height: 48px; + text-align: center; +} +.#{$baseClass}__container { + position: relative; + width: 100vw; + .#{$baseClass}__action__con { + display: flex; + flex-direction: column; + justify-items: start; + text-align: center; + .#{$baseClass}__cancel { + background: #000; + } + .#{$baseClass}__description { + padding: 20px; + color: $grey; + font-size: 14px; + border-bottom: 1px solid $grey-background; + } + .#{$baseClass}__action__item { + line-height: 22px; + display: block; + width: 100%; + padding: 14px 16px; + font-size: 16px; + background-color: #fff; + border: none; + cursor: pointer; + &:active { + background-color: $grey-background; + } + + .#{$baseClass}__action__item__name { + font-size: 16px; + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + &__danger { + color: $danger; + } + .loading { + svg { + circle { + stroke: #c8c9cc !important; + } + } + } + } + .#{$baseClass}__action__item__subName { + font-size: 12px; + color: $grey; + } + } + } +} diff --git a/src/components/ActionSheet/index.stories.tsx b/src/components/ActionSheet/index.stories.tsx new file mode 100644 index 00000000..2e0237f8 --- /dev/null +++ b/src/components/ActionSheet/index.stories.tsx @@ -0,0 +1,250 @@ +/* + * @Author: zhaohui + * @Date: 2021-05-13 18:18:19 + * @LastEditTime: 2021-05-30 15:51:25 + * @LastEditors: zhaohui + * @Description: + * @FilePath: /vant-react/src/components/ActionSheet/index.stories.tsx + */ +import React, { useState } from 'react'; +import ActionSheet from '.'; +import { ActionItem } from './types'; +import Cell from '../Cell'; +import '../../styles/stories.scss'; +import Toast from '../Toast'; + +export default { + title: 'ActionSheet', + component: ActionSheet +}; + +export const ActionSheetDefault = () => { + const [visible, setVisible] = useState(false); + const actions: ActionItem[] = [ + { + name: 'Option1', + value: 1, + callback: (item: ActionItem) => { + Toast.info({ message: item.name }); + setVisible(false); + } + }, + { + name: 'Option2', + value: 2, + subname: 'This is a description', + callback: (item: ActionItem) => { + Toast.info({ message: item.name }); + setVisible(false); + } + } + ]; + return ( +
+ { + setVisible(true); + } + }} + /> + setVisible(false)} + actions={actions} + /> +
+ ); +}; +export const ActionSheetWithStatus = () => { + const [visible, setVisible] = useState(false); + const actions: ActionItem[] = [ + { + name: 'Disabled', + value: 1, + disabled: true, + callback: (item: ActionItem) => { + Toast.info({ message: item.name }); + setVisible(false); + } + }, + { + name: 'Loading...', + value: 2, + loading: true, + callback: (item: ActionItem) => { + Toast.info({ message: item.name }); + setVisible(false); + } + }, + { + name: 'Danger...', + value: 3, + danger: true, + callback: (item: ActionItem) => { + Toast.info({ message: item.name }); + setVisible(false); + } + } + ]; + return ( +
+ { + setVisible(true); + } + }} + /> + setVisible(false)} + actions={actions} + /> +
+ ); +}; +export const ActionSheetWithDiffrentButton = () => { + const [visibleTitle, setVisibleTitle] = useState(false); + const [visibleDescription, setVisibleDescription] = useState(false); + const [visibleCancel, setVisibleCancel] = useState(false); + const [visibleCancelIcon, setVisibleCancelIcon] = useState(false); + const actionsTitle: ActionItem[] = [ + { + name: 'Option', + value: 1, + callback: (item: ActionItem) => { + Toast.info({ message: item.name }); + setVisibleTitle(false); + } + } + ]; + const actionsCancel: ActionItem[] = [ + { + name: 'Option', + value: 1, + callback: (item: ActionItem) => { + Toast.info({ message: item.name }); + setVisibleTitle(false); + } + } + ]; + const actionsCancelIcon: ActionItem[] = [ + { + name: 'Option', + value: 1, + callback: (item: ActionItem) => { + Toast.info({ message: item.name }); + setVisibleTitle(false); + } + } + ]; + const actionTitle: ActionItem[] = [ + { + name: 'Option', + value: 1, + callback: (item: ActionItem) => { + Toast.info({ message: item.name }); + setVisibleTitle(false); + } + } + ]; + const actionsDescription: ActionItem[] = [ + { + name: 'Option', + value: 1, + callback: (item: ActionItem) => { + Toast.info({ message: item.name }); + setVisibleTitle(false); + } + } + ]; + return ( +
+ { + setVisibleTitle(true); + } + }} + /> + { + setVisibleDescription(true); + } + }} + /> + { + setVisibleCancel(true); + } + }} + /> + { + setVisibleCancelIcon(true); + } + }} + /> + setVisibleTitle(false)} + actions={actionTitle} + title='This is title' + /> + setVisibleDescription(false)} + actions={actionsDescription} + description='This is description' + /> + setVisibleCancel(false)} + actions={actionsCancel} + /> + setVisibleCancelIcon(false)} + closeable + actions={actionsCancelIcon} + /> + setVisibleCancelIcon(false)} + closeable + actions={actionsTitle} + /> +
+ ); +}; diff --git a/src/components/ActionSheet/index.tsx b/src/components/ActionSheet/index.tsx new file mode 100644 index 00000000..85d27562 --- /dev/null +++ b/src/components/ActionSheet/index.tsx @@ -0,0 +1,35 @@ +/* + * @Author: zhaohui + * @Date: 2021-05-29 11:24:50 + * @LastEditTime: 2021-05-30 15:44:24 + * @LastEditors: zhaohui + * @Description: + * @FilePath: /vant-react/src/components/ActionSheet/index.tsx + */ +import React, { useState, useEffect } from 'react'; +import Popup from '../Popup'; +import { ActionSheetProps } from './types'; +import ActionSheet from './ActionSheet'; + +const ActionSheetContainer = (props: ActionSheetProps) => { + const [_visible, setVisible] = useState(false); + const _maskClick = () => { + if (props.maskClick) { + props.maskClick(); + } + }; + useEffect(() => { + setVisible(props.visible); + }); + return ( +
+ _maskClick()} + content={} + /> +
+ ); +}; +export default ActionSheetContainer; diff --git a/src/components/ActionSheet/types.ts b/src/components/ActionSheet/types.ts new file mode 100644 index 00000000..24d98de8 --- /dev/null +++ b/src/components/ActionSheet/types.ts @@ -0,0 +1,36 @@ +/* + * @Author: zhaohui + * @Date: 2021-05-29 11:34:24 + * @LastEditTime: 2021-05-30 14:47:58 + * @LastEditors: zhaohui + * @Description: + * @FilePath: /vant-react/src/components/ActionSheet/types.ts + */ +import { LoadingTypes } from '../Button/types'; + +export interface ActionSheetProps { + visible: boolean; + actions?: ActionItem[]; + title?: string | React.ReactNode; + cancelText?: string | React.ReactNode; + description?: string | React.ReactNode; + closeIcon?: string | React.ReactNode; + safeAreaInsetBottom?: boolean; + closeable?: boolean; + maskClick?: Function; // click mask + cancelClick?: Function; +} + +export interface ActionItem { + name: string | React.ReactNode; + value: any; + subname?: string | React.ReactNode; + color?: string; + className?: string; + loading?: boolean; + loadingType?: LoadingTypes; + disabled?: boolean; + callback?: Function; + danger?: boolean; +} +export const BaseClass = 'vant-action-sheet'; diff --git a/src/index.tsx b/src/index.tsx index 0c4568ca..703c19ca 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -13,6 +13,7 @@ import Checkbox from './components/Checkbox'; import Radio from './components/Radio'; import Stepper from './components/Stepper'; import Toast from './components/Toast'; +import ActionSheet from './components/ActionSheet'; export { default as Button } from './components/Button'; export { default as Icon } from './components/Icons'; @@ -29,6 +30,7 @@ export { default as Checkbox } from './components/Checkbox'; export { default as Radio } from './components/Radio'; export { default as Stepper } from './components/Stepper'; export { default as Toast } from './components/Toast'; +export { default as ActionSheet } from './components/ActionSheet'; const Vant = { Button, @@ -45,7 +47,8 @@ const Vant = { Checkbox, Radio, Stepper, - Toast + Toast, + ActionSheet }; export default Vant;