diff --git a/src/config.json b/src/config.json index 9d39f4c84ab62d87fc4f98e26c0b88a1ac211c69..b02f1221fca1c9e93b4b8c9b80029cbc652d7d69 100644 --- a/src/config.json +++ b/src/config.json @@ -283,6 +283,16 @@ "desc": "弹出层容器,用于展示弹窗、信息提示等内容,支持多个弹出层叠加展示", "author": "szg2008" }, + { + "version": "1.0.0", + "name": "ActionSheet", + "type": "component", + "cName": "动作面板", + "desc": "从底部弹出的动作菜单面板。", + "sort": 11, + "show": true, + "author": "dsj" + }, { "version": "1.0.0", "name": "NoticeBar", diff --git a/src/packages/actionsheet/actionsheet.scss b/src/packages/actionsheet/actionsheet.scss new file mode 100644 index 0000000000000000000000000000000000000000..ad9a8f2ca7ca7dac61969071151463d9ac28802f --- /dev/null +++ b/src/packages/actionsheet/actionsheet.scss @@ -0,0 +1,68 @@ +.nut-actionsheet { + display: block; + .nut-actionsheet__title { + display: block; + padding: 10px; + margin: 0; + text-align: center; + background-color: $white; + border-bottom: 1px solid $light-color; + font-size: $font-size-base; + color: $title-color; + } + + .nut-actionsheet-modal { + .nut-actionsheet__title, + .nut-actionsheet-sub-title { + padding: 5px 0; + } + + .nut-actionsheet-sub-title { + display: block; + font-size: $font-size-small; + color: $title-color; + margin-inline-start: 0px; + } + } + + .nut-actionsheet__menu { + display: block; + list-style: none; + padding: 0; + margin: 0; + } + + .nut-actionsheet__cancel, + .nut-actionsheet__item { + display: block; + // height: 24px; + padding: 10px; + line-height: 24px; + font-size: $font-size-base; + color: $title-color; + text-align: center; + background-color: #fff; + cursor: pointer; + } + + .desc { + font-size: $font-size-2; + color: #999; + } + + .subdesc { + display: block; + font-size: $font-size-small; + color: #999; + } + + .nut-actionsheet__item-disabled { + color: #e1e1e1 !important; + cursor: not-allowed; + } + + .nut-actionsheet__cancel { + margin-top: 5px; + border-top: 1px solid $light-color; + } +} diff --git a/src/packages/actionsheet/actionsheet.tsx b/src/packages/actionsheet/actionsheet.tsx new file mode 100644 index 0000000000000000000000000000000000000000..234cbe89ca0059f664000cae5fd49c1d04eebc4b --- /dev/null +++ b/src/packages/actionsheet/actionsheet.tsx @@ -0,0 +1,121 @@ +import React, { FunctionComponent, useState, useEffect } from 'react' +import Popup from '@/packages/popup' +import './actionsheet.scss' +import bem from '@/utils/bem' + +export type ItemType = { [key: string]: T } + +export interface ActionSheetProps { + cancelTxt: string + optionTag: string + optionSubTag: string + chooseTagValue: string + title: string + color: string + description: string + menuItems: ItemType[] + cancel: () => void + choose: (item: any, index: number) => void + visible: boolean + className: string + style: React.CSSProperties +} +const defaultProps = { + cancelTxt: '', + optionTag: 'name', + optionSubTag: 'subname', + chooseTagValue: '', + title: '', + color: '#ee0a24', + description: '', + menuItems: [], + cancel: () => {}, + choose: () => {}, + visible: false, + className: '', + style: {}, +} as ActionSheetProps +export const ActionSheet: FunctionComponent< + Partial & React.HTMLAttributes +> = (props) => { + const { + cancelTxt, + optionTag, + optionSubTag, + chooseTagValue, + title, + color, + description, + menuItems, + cancel, + choose, + visible, + className, + style, + ...rest + } = { ...defaultProps, ...props } + + const [isShow, setIsShow] = useState(false) + const b = bem('actionsheet') + + useEffect(() => { + setIsShow(visible) + }, [visible]) + + const isHighlight = (item: ItemType) => { + return props.chooseTagValue && props.chooseTagValue === item[props.optionTag || 'name'] + ? props.color + : '#1a1a1a' + } + + const cancelActionSheet = () => { + cancel && cancel() + } + + const chooseItem = (item: ItemType, index: number) => { + if (!item.disable) { + choose && choose(item, index) + } + } + + return ( + { + cancel && cancel() + }} + > +
+ {title &&
{title}
} + {description &&
{description}
} + {menuItems.length ? ( +
+ {menuItems.map((item, index) => { + return ( +
chooseItem(item, index)} + > + {item[optionTag]} +
{item[optionSubTag]}
+
+ ) + })} +
+ ) : null} + {cancelTxt && ( +
cancelActionSheet()}> + {cancelTxt} +
+ )} +
+
+ ) +} + +ActionSheet.defaultProps = defaultProps +ActionSheet.displayName = 'NutActionSheet' diff --git a/src/packages/actionsheet/demo.tsx b/src/packages/actionsheet/demo.tsx new file mode 100644 index 0000000000000000000000000000000000000000..619720fb6311ea61e3ba85527417ba1f0666b494 --- /dev/null +++ b/src/packages/actionsheet/demo.tsx @@ -0,0 +1,136 @@ +import React, { useState, useEffect } from 'react' +import { ActionSheet, ItemType } from './actionsheet' +import Cell from '@/packages/cell' +interface Item { + name: string + subname?: string + disable?: boolean +} + +const ActionSheetDemo = () => { + const [isVisible1, setIsVisible1] = useState(false) + const [isVisible2, setIsVisible2] = useState(false) + const [isVisible3, setIsVisible3] = useState(false) + const [isVisible4, setIsVisible4] = useState(false) + const [val1, setVal1] = useState('') + const [val2, setVal2] = useState('') + const [val3, setVal3] = useState('') + const menuItemsOne: ItemType[] = [ + { + name: '选项一', + }, + { + name: '选项二', + }, + { + name: '选项三', + }, + ] + const menuItemsTwo: ItemType[] = [ + { + name: '选项一', + }, + { + name: '选项二', + }, + { + name: '选项三', + subname: '描述信息', + }, + ] + const menuItemsThree: ItemType[] = [ + { + name: '着色选项', + }, + { + name: '禁用选项', + disable: true, + }, + ] + + const chooseItem = (itemParams: any) => { + console.log(itemParams.name, 'itemParams') + setVal1(itemParams.name) + setIsVisible1(false) + } + + const chooseItemTwo = (itemParams: Item) => { + setVal2(itemParams.name) + setIsVisible2(false) + } + const chooseItemThree = (itemParams: Item) => { + setVal3(itemParams.name) + setIsVisible3(false) + } + + return ( + <> +
+

基本用法

+ setIsVisible1(!isVisible1)}> + + + +
{val1}
+
+ setIsVisible2(!isVisible2)}> + + + +
{val2}
+
+ setIsVisible3(!isVisible3)}> + + + +
{val3}
+
+

选项状态

+ + setIsVisible4(!isVisible4)}> + + + + + + {/* demo 基础用法 */} + setIsVisible1(false)} + > + {/* demo(带取消按钮) */} + setIsVisible2(false)} + > + {/* 展示描述信息 */} + setIsVisible3(false)} + > + {/* demo 选项状态 */} + setIsVisible4(false)} + menuItems={menuItemsThree} + chooseTagValue="着色选项" + choose={() => { + setIsVisible4(false) + }} + > +
+ + ) +} + +export default ActionSheetDemo diff --git a/src/packages/actionsheet/doc.md b/src/packages/actionsheet/doc.md new file mode 100644 index 0000000000000000000000000000000000000000..9d68fce3c82196745d4e3aa97e7fe88ff0717e26 --- /dev/null +++ b/src/packages/actionsheet/doc.md @@ -0,0 +1,165 @@ +# ActionSheet 动作面板 + + +### 介绍 +从底部弹出的动作菜单面板。 + +### 安装 + +``` javascript +import { ActionSheet } from '@nutui/nutui'; +``` +## 代码示例 + +### 基本用法 + +默认 +``` tsx + setIsVisible1(!isVisible1)}> + + + +
{val1}
+
+ + setIsVisible1(false)} +>å +``` + +### 展示取消按钮 +``` tsx + setIsVisible2(!isVisible2)}> + + + +
{val2}
+
+ + setIsVisible2(false)} +> +``` +### 展示描述信息 +```tsx + setIsVisible3(!isVisible3)}> + + + +
{val3}
+
+ setIsVisible3(false)} +> +``` + +### 选项状态 +```tsx + setIsVisible4(!isVisible4)}> + + + + + setIsVisible4(false)} + menuItems={menuItemsThree} + chooseTagValue="着色选项" + choose={() => { + setIsVisible4(false) + }} +> +``` + +```javascript + const [isVisible1, setIsVisible1] = useState(false) + const [isVisible2, setIsVisible2] = useState(false) + const [isVisible3, setIsVisible3] = useState(false) + const [isVisible4, setIsVisible4] = useState(false) + const [val1, setVal1] = useState('') + const [val2, setVal2] = useState('') + const [val3, setVal3] = useState('') + const menuItemsOne: ItemType[] = [ + { + name: '选项一', + }, + { + name: '选项二', + }, + { + name: '选项三', + }, + ] + const menuItemsTwo: ItemType[] = [ + { + name: '选项一', + }, + { + name: '选项二', + }, + { + name: '选项三', + subname: '描述信息', + }, + ] + const menuItemsThree: ItemType[] = [ + { + name: '着色选项', + }, + { + name: '禁用选项', + disable: true, + }, + ] + + const chooseItem = (itemParams: any) => { + console.log(itemParams.name, 'itemParams') + setVal1(itemParams.name) + setIsVisible1(false) + } + + const chooseItemTwo = (itemParams: Item) => { + setVal2(itemParams.name) + setIsVisible2(false) + } + const chooseItemThree = (itemParams: Item) => { + setVal3(itemParams.name) + setIsVisible3(false) + } + +``` + +## Prop + +| 字段 | 说明 | 类型 | 默认值 | +|------------------|----------------------------------------|---------|-----------| +| cancelTxt | 取消文案 | String | '取消' | +| menuItems | 列表项 | Array | [ ] | +| optionTag | 设置列表项展示使用参数 | String | 'name' | +| visible | 遮罩层可见 | Boolean | false | +| optionSubTag | 设置列表项描述展示使用参数 | String | 'subname' | +| chooseTagValue | 设置选中项的值,和'option-tag'的值对应 | String | '' | +| title | 设置列表项标题 | String | '' | +| description | 设置列表项副标题/描述 | String | '' | +| color | 高亮颜色 | String | '#ee0a24' | + + +## Event + +| 字段 | 说明 | 回调参数 | +|--------|--------------------|-----------------------------------| +| choose | 选择之后触发 | 选中列表项item, 选中的索引值index | +| cancel | 点击取消文案时触发 | 无 | \ No newline at end of file diff --git a/src/packages/actionsheet/index.ts b/src/packages/actionsheet/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..4cacdaa26233398f4ec1bbeeaa39fb20c1ba175f --- /dev/null +++ b/src/packages/actionsheet/index.ts @@ -0,0 +1,2 @@ +import { ActionSheet } from './actionsheet' +export default ActionSheet diff --git a/src/packages/overlay/overlay.tsx b/src/packages/overlay/overlay.tsx index 19c42c83bb3f5c865f945a896ee7a9860971ec7f..0748e9082f54dc781b7f2db8beb7e6641f91dd86 100644 --- a/src/packages/overlay/overlay.tsx +++ b/src/packages/overlay/overlay.tsx @@ -24,9 +24,6 @@ export const defaultOverlayProps = { export const Overlay: FunctionComponent< Partial & React.HTMLAttributes > = (props) => { - const [show, setShow] = useState(false) - const renderRef = useRef(true) - const intervalRef = useRef(0) const { children, zIndex, @@ -41,9 +38,12 @@ export const Overlay: FunctionComponent< ...defaultOverlayProps, ...props, } + const [show, setShow] = useState(visible) + const renderRef = useRef(true) + const intervalRef = useRef(0) useEffect(() => { - setShow(false) + visible && setShow(visible) lock() }, [visible]) @@ -61,7 +61,7 @@ export const Overlay: FunctionComponent< 'overlay-fade-leave-active': !renderRef.current && !visible, 'overlay-fade-enter-active': visible, 'first-render': renderRef.current && !visible, - 'hidden-render': show, + 'hidden-render': !visible, }, overlayClass, b('') @@ -86,7 +86,7 @@ export const Overlay: FunctionComponent< props.onClick && props.onClick(e) renderRef.current = false let id = setTimeout(() => { - setShow(true) + setShow(!visible) }, duration * 1000 * 0.8) intervalRef.current = id } diff --git a/src/packages/popup/popup.tsx b/src/packages/popup/popup.tsx index 46f377b075e83d1aaeacee31f06178f416937467..4cb715ac3a22c5ab17f6d2d7842c5969b24c6f8d 100644 --- a/src/packages/popup/popup.tsx +++ b/src/packages/popup/popup.tsx @@ -129,7 +129,7 @@ export const Popup: FunctionComponent & React.HTMLAttributes // if(zIndex !== undefined) { // _zIndex = +zIndex; // } - setInnerVisible(visible) + setInnerVisible(true) setIndex(++_zIndex) } if (destroyOnClose) { @@ -139,8 +139,9 @@ export const Popup: FunctionComponent & React.HTMLAttributes } const close = () => { + console.log('close', innerVisible, visible) if (innerVisible) { - setInnerVisible(!visible) + setInnerVisible(false) if (destroyOnClose) { setTimeout(() => { setShowChildren(false) @@ -175,7 +176,9 @@ export const Popup: FunctionComponent & React.HTMLAttributes } useEffect(() => { + console.log('popup', visible) visible && open() + !visible && close() }, [visible]) useEffect(() => {