-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4 from TDesignOteam/dev
feat(ActionSheet): 添加actionsheet组件
- Loading branch information
Showing
8 changed files
with
368 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
:: BASE_DOC :: | ||
|
||
## API | ||
### Base Props | ||
|
||
临时md,后期会自动生成 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<ActionSheetProps> & 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 ( | ||
<View className="bg px16 py8"> | ||
<Text className={`text4 ${align === 'left' ? '' : 'textCenter'}`}>{title}</Text> | ||
</View> | ||
); | ||
} | ||
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 : ( | ||
<Touchable onPress={() => ActionSheet.hide(ActionSheet.actionSheetId)}> | ||
<View | ||
className="mt4 bg flexCenter" | ||
style={{ | ||
height: 50 + (insets?.bottom || 0), | ||
paddingBottom: insets?.bottom, | ||
}} | ||
> | ||
<Text className="bg text3 textCenter">{cancelText}</Text> | ||
</View> | ||
</Touchable> | ||
); | ||
}, [cancelText, hideCancel, insets]); | ||
|
||
const onItemPress = (item: ActionSheetItem, index: number) => { | ||
onSelected?.(item, index); | ||
}; | ||
|
||
return ( | ||
<View className="bgPage" style={[styles.container, style]}> | ||
{renderTitle()} | ||
{items?.map((item, index) => ( | ||
<Touchable key={index} disabled={!!item.disable} onPress={() => onItemPress(item, index)}> | ||
<View | ||
className={`bt1 px16 bg ${align === 'left' ? 'flexStartH flexCenterH' : 'flexCenter'}`} | ||
style={{ height: 50 }} | ||
> | ||
<Text | ||
className="text3" | ||
style={{ | ||
color: getColor(item.theme), | ||
paddingBottom: !hideCancel && index === items.length - 1 ? 0 : insets?.bottom || 0, | ||
}} | ||
> | ||
{item.text} | ||
</Text> | ||
{item.tip ? ( | ||
<Text | ||
className="textCenter" | ||
style={{ | ||
fontSize: theme.fontSize.base, | ||
color: theme.colors.fontGray2, | ||
}} | ||
> | ||
{item.tip} | ||
</Text> | ||
) : null} | ||
</View> | ||
</Touchable> | ||
))} | ||
{renderCancel()} | ||
</View> | ||
); | ||
}; | ||
|
||
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(<ActionSheet {...mergedConfig} />, { | ||
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); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 ( | ||
<> | ||
<Section> | ||
<P>用于展示用户头像信息,除了纯展示也可点击进入个人详情等操作。</P> | ||
<H3>1.类型</H3> | ||
<CodeSpace> | ||
<View className="gapY10"> | ||
<Button | ||
content={'常规使用'} | ||
onPress={() => { | ||
const id = ActionSheet.show({ | ||
title: '常规使用', | ||
items: [{ text: '第一项' }, { text: '第二项' }, { text: '第三项' }, { text: '第四项' }], | ||
onSelected: (item) => { | ||
console.log(item); | ||
ActionSheet.hide(id); | ||
}, | ||
}); | ||
}} | ||
/> | ||
<Button | ||
content={'选项说明'} | ||
onPress={() => { | ||
const id = ActionSheet.show({ | ||
title: '选项说明', | ||
items: [ | ||
{ text: '第一项', theme: 'info' }, | ||
{ text: '第二项', theme: 'info' }, | ||
{ text: '第三项', theme: 'error', tip: '说明' }, | ||
{ text: '第四项', theme: 'info', tip: '说明' }, | ||
], | ||
onSelected: (item) => { | ||
console.log(item); | ||
ActionSheet.hide(id); | ||
}, | ||
}); | ||
}} | ||
/> | ||
<Button | ||
content={'隐藏取消按钮'} | ||
onPress={() => { | ||
const id = ActionSheet.show({ | ||
hideCancel: true, | ||
title: '隐藏取消按钮', | ||
items: [{ text: '第一项' }, { text: '第二项' }, { text: '第三项' }, { text: '第四项' }], | ||
onSelected: (item) => { | ||
console.log(item); | ||
ActionSheet.hide(id); | ||
}, | ||
}); | ||
}} | ||
/> | ||
<Button | ||
content={'取消按钮文字自定义'} | ||
onPress={() => { | ||
const id = ActionSheet.show({ | ||
cancelText: '自定义', | ||
title: '取消按钮文字自定义', | ||
items: [{ text: '第一项' }, { text: '第二项' }, { text: '第三项' }, { text: '第四项' }], | ||
onSelected: (item) => { | ||
console.log(item); | ||
ActionSheet.hide(id); | ||
}, | ||
}); | ||
}} | ||
/> | ||
<Button | ||
content={'点击蒙层不关闭'} | ||
onPress={() => { | ||
const id = ActionSheet.show({ | ||
closeOnOverlay: false, | ||
title: '点击蒙层不关闭', | ||
items: [{ text: '第一项' }, { text: '第二项' }, { text: '第三项' }, { text: '第四项' }], | ||
onSelected: (item) => { | ||
console.log(item); | ||
ActionSheet.hide(id); | ||
}, | ||
}); | ||
}} | ||
/> | ||
</View> | ||
</CodeSpace> | ||
</Section> | ||
<Section> | ||
<H3>2.样式</H3> | ||
<CodeSpace> | ||
<View className="gapY10"> | ||
<Button | ||
content={'选项禁用'} | ||
onPress={() => { | ||
const id = ActionSheet.show({ | ||
title: '选项禁用', | ||
items: [ | ||
{ text: '第一项' }, | ||
{ text: '第二项', disable: true }, | ||
{ text: '第三项', disable: true }, | ||
{ text: '第四项' }, | ||
], | ||
onSelected: (item) => { | ||
console.log(item); | ||
ActionSheet.hide(id); | ||
}, | ||
}); | ||
}} | ||
/> | ||
<Button | ||
content={'选项主题'} | ||
onPress={() => { | ||
const id = ActionSheet.show({ | ||
title: '选项主题', | ||
items: [ | ||
{ text: '第一项', theme: 'warning' }, | ||
{ text: '第二项', theme: 'error' }, | ||
{ text: '第三项', theme: 'success' }, | ||
{ text: '第四项', theme: 'info' }, | ||
], | ||
onSelected: (item) => { | ||
console.log(item); | ||
ActionSheet.hide(id); | ||
}, | ||
}); | ||
}} | ||
/> | ||
<Button | ||
content={'选项左对齐'} | ||
onPress={() => { | ||
const id = ActionSheet.show({ | ||
align: 'left', | ||
title: '选项左对齐', | ||
items: [{ text: '第一项' }, { text: '第二项' }, { text: '第三项' }, { text: '第四项' }], | ||
onSelected: (item) => { | ||
console.log(item); | ||
ActionSheet.hide(id); | ||
}, | ||
}); | ||
}} | ||
/> | ||
</View> | ||
</CodeSpace> | ||
</Section> | ||
</> | ||
); | ||
}; | ||
|
||
export default Demo; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export { ActionSheet } from './ActionSheet'; | ||
export type { ActionSheetProps } from './types'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<void>; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters