From 933a05462eefd58a4f0aa3f7e02f2ec05f2f4e07 Mon Sep 17 00:00:00 2001 From: yatessss <897969073@qq.com> Date: Tue, 6 Feb 2024 19:42:33 +0800 Subject: [PATCH] =?UTF-8?q?feat(ActionSheet):=20=E6=B7=BB=E5=8A=A0actionsh?= =?UTF-8?q?eet=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example/src/config.json | 4 + package.json | 1 + src/components/ActionSheet/ActionSheet.md | 7 + src/components/ActionSheet/ActionSheet.tsx | 140 ++++++++++++++++ src/components/ActionSheet/_example/index.tsx | 156 ++++++++++++++++++ src/components/ActionSheet/index.tsx | 2 + src/components/ActionSheet/types.ts | 57 +++++++ src/components/index.ts | 1 + 8 files changed, 368 insertions(+) create mode 100644 src/components/ActionSheet/ActionSheet.md create mode 100644 src/components/ActionSheet/ActionSheet.tsx create mode 100644 src/components/ActionSheet/_example/index.tsx create mode 100644 src/components/ActionSheet/index.tsx create mode 100644 src/components/ActionSheet/types.ts diff --git a/example/src/config.json b/example/src/config.json index 45fa2b2..1746fda 100644 --- a/example/src/config.json +++ b/example/src/config.json @@ -64,6 +64,10 @@ { "title": "消息提醒", "children": [ + { + "title": "ActionSheet 动作面板", + "key": "ActionSheet" + }, { "title": "Dialog 对话框", "key": "Dialog" diff --git a/package.json b/package.json index f281da6..6c62627 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "react-native": "0.71.3", "react-native-gesture-handler": "^2.14.0", "react-native-reanimated": "^3.0.2", + "react-native-safe-area-context": "^4.9.0", "tdesign-icons-react-native": "^0.0.1" }, "devDependencies": { diff --git a/src/components/ActionSheet/ActionSheet.md b/src/components/ActionSheet/ActionSheet.md new file mode 100644 index 0000000..9f10779 --- /dev/null +++ b/src/components/ActionSheet/ActionSheet.md @@ -0,0 +1,7 @@ +:: BASE_DOC :: + +## API +### Base Props + +临时md,后期会自动生成 + diff --git a/src/components/ActionSheet/ActionSheet.tsx b/src/components/ActionSheet/ActionSheet.tsx new file mode 100644 index 0000000..31d813a --- /dev/null +++ b/src/components/ActionSheet/ActionSheet.tsx @@ -0,0 +1,140 @@ +import React, { useCallback, useContext } from 'react'; +import { StyleSheet } from 'react-native'; +import { isString } from 'lodash'; +import { SafeAreaInsetsContext } from 'react-native-safe-area-context'; +import { View, Text } from '../Base'; +import { Touchable } from '../Touchable'; +import { Popup } from '../Popup'; +import { ThemeContext } from '../../theme'; +import { ActionSheetProps, ActionSheetStaticProps, ActionSheetItem, ActionSheetItemTheme } from './types'; + +const styles = StyleSheet.create({ + container: {}, +}); + +export const ActionSheet: React.FunctionComponent & ActionSheetStaticProps = (props) => { + const { style, title, align, items, onSelected, cancelText, hideCancel } = props; + const { theme } = useContext(ThemeContext); + const insets = useContext(SafeAreaInsetsContext); + + const renderTitle = useCallback(() => { + if (isString(title)) { + return ( + + {title} + + ); + } + if (React.isValidElement(title)) { + return title; + } + return null; + }, [title, align]); + + const getColor = useCallback( + (itemTheme?: ActionSheetItemTheme) => { + switch (itemTheme) { + case 'success': + return theme.colors.success5; + case 'error': + return theme.colors.error6; + case 'warning': + return theme.colors.warning5; + case 'info': + return theme.colors.brand7; + default: + return theme.colors.fontGray1; + } + }, + [theme], + ); + + const renderCancel = useCallback(() => { + return hideCancel ? null : ( + ActionSheet.hide(ActionSheet.actionSheetId)}> + + {cancelText} + + + ); + }, [cancelText, hideCancel, insets]); + + const onItemPress = (item: ActionSheetItem, index: number) => { + onSelected?.(item, index); + }; + + return ( + + {renderTitle()} + {items?.map((item, index) => ( + onItemPress(item, index)}> + + + {item.text} + + {item.tip ? ( + + {item.tip} + + ) : null} + + + ))} + {renderCancel()} + + ); +}; + +ActionSheet.defaultProps = { + align: 'center', + cancelText: '取消', + closeOnOverlay: true, +}; + +ActionSheet.show = (config) => { + // 整体内容高度 + 安全距离 + const offsetY = (config.title ? 38 : 0) + (config?.items?.length ? config.items.length * 50 : 0) + 50 + 40; + const mergedConfig = { ...ActionSheet.defaultProps, ...config }; + + ActionSheet.actionSheetId = Popup.show(, { + wrapperStyle: { + height: 'auto', + borderTopRightRadius: 8, + borderTopLeftRadius: 8, + overflow: 'hidden', + }, + placement: 'bottom', + animation: { + from: { transform: [{ translateY: offsetY }] }, + to: { transform: [{ translateY: 0 }] }, + }, + closeOnOverlay: mergedConfig.closeOnOverlay, + showOverlay: true, + }); + return ActionSheet.actionSheetId; +}; + +ActionSheet.hide = (id) => { + return Popup.hide(id); +}; diff --git a/src/components/ActionSheet/_example/index.tsx b/src/components/ActionSheet/_example/index.tsx new file mode 100644 index 0000000..1fffb0c --- /dev/null +++ b/src/components/ActionSheet/_example/index.tsx @@ -0,0 +1,156 @@ +/** + * title: ActionSheet 动作面板 + * description: 由用户操作后触发的一种特定的模态弹出框 ,呈现一组与当前情境相关的两个或多个选项。 + * spline: base + * isComponent: true + * toc: false + */ +import { View, ActionSheet, Button } from 'tdesign-react-native/components'; +import { Section, CodeSpace, H3, P } from '@src/../example/src/components'; + +const Demo = () => { + return ( + <> +
+

用于展示用户头像信息,除了纯展示也可点击进入个人详情等操作。

+

1.类型

+ + +
+
+

2.样式

+ + +
+ + ); +}; + +export default Demo; diff --git a/src/components/ActionSheet/index.tsx b/src/components/ActionSheet/index.tsx new file mode 100644 index 0000000..c2926be --- /dev/null +++ b/src/components/ActionSheet/index.tsx @@ -0,0 +1,2 @@ +export { ActionSheet } from './ActionSheet'; +export type { ActionSheetProps } from './types'; diff --git a/src/components/ActionSheet/types.ts b/src/components/ActionSheet/types.ts new file mode 100644 index 0000000..de531a0 --- /dev/null +++ b/src/components/ActionSheet/types.ts @@ -0,0 +1,57 @@ +import type { ViewStyle } from 'react-native'; +import { ReactElement } from 'react'; + +export type ActionSheetItemTheme = 'info' | 'success' | 'warning' | 'error'; + +export type ActionSheetItem = { + tip?: string; + text?: string; + theme?: ActionSheetItemTheme; + disable?: boolean; + [key: string]: any; +}; + +export type ActionSheetProps = { + /** + * style + */ + style?: ViewStyle; + /** + * 水平对齐方式 + * @default center + */ + align?: 'center' | 'left'; + /** + * 取消按钮的文本 + * @default 取消 + */ + cancelText?: string; + /** + * 是否显示取消按钮 + * @default true + */ + hideCancel?: boolean; + /** + * 动作面板描述 + */ + title?: string | ReactElement | null; + /** + * 点击蒙层关闭 + * @default true + */ + closeOnOverlay?: boolean; + /** + * 菜单列表 + */ + items: ActionSheetItem[]; + /** + * 点击菜单某项回调 + */ + onSelected?: (item?: ActionSheetItem, index?: number) => void; +}; + +export type ActionSheetStaticProps = { + actionSheetId?: number; + show: (config: ActionSheetProps) => number; + hide: (id?: number) => Promise; +}; diff --git a/src/components/index.ts b/src/components/index.ts index d26a4f0..386a1db 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -13,3 +13,4 @@ export * from './Toast'; export * from './Dialog'; export * from './Avatar'; export * from './Image'; +export * from './ActionSheet';