Skip to content

Commit

Permalink
feat(ActionSheet): Add new component. (#205)
Browse files Browse the repository at this point in the history
* 编写选项卡组件

* 类型名称请调整,添加组件文档在网站上展示

* #162修复报错

* fix:#162修复报错

* SpeedDial 悬浮标记

* 优化类型

* feat(ActionSheet): Add new component.
  • Loading branch information
cuilanxin committed Sep 6, 2021
1 parent d3f569e commit 38fae82
Show file tree
Hide file tree
Showing 9 changed files with 352 additions and 0 deletions.
8 changes: 8 additions & 0 deletions example/examples/src/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -403,4 +403,12 @@ export const stackPageData: Routes[] = [
description: '可折叠卡片列表',
},
},
{
name: 'ActionSheet',
component: require('./routes/ActionSheet').default,
params: {
title: 'ActionSheet 动作面板',
description: '该组件提供了一种动作面板, 底部缓缓出现',
},
},
];
64 changes: 64 additions & 0 deletions example/examples/src/routes/ActionSheet/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import React, { Component } from 'react';
import { StyleSheet, View, } from 'react-native';
import Layout, { Container } from '../../Layout';
import { ActionSheet, Button, ActionSheetItem, Toast, S } from '@uiw/react-native';
import { ComProps } from '../../routes';

const { Header, Body, Card, Footer } = Layout;

export interface IndexProps extends ComProps { }
export interface IndexState {
visible: boolean;
}

export default class Index extends Component<IndexProps, IndexState> {
static state: IndexState;
constructor(props: IndexProps) {
super(props);
this.state = {
visible: false,
};
}
onOpen = () => {
this.setState({ visible: true });
}
onCancel = () => {
this.setState({ visible: false });
};
render() {
const { route } = this.props;
const description = route.params.description;
const title = route.params.title;
return (
<Container>
<Layout>
<Header title={title} description={description} />
<Body>
<View style={styles.divider} />
<Button onPress={this.onOpen}>打开 ActionSheet</Button>
<ActionSheet
visible={this.state.visible}
// onCancel={true}
>
<ActionSheetItem onPress={() => Toast.info('你点击了按钮一', 2, 'info')}>按钮一</ActionSheetItem>
<ActionSheetItem onPress={() => Toast.info('你点击了按钮二', 2, 'info')}>按钮二</ActionSheetItem>
<ActionSheetItem onPress={this.onCancel}>按钮三</ActionSheetItem>
</ActionSheet>
</Body>
<Footer />
</Layout>
</Container>
);
}
}

const styles = StyleSheet.create({
card: {
backgroundColor: '#fff',
paddingLeft: 20,
paddingRight: 20,
},
divider: {
marginVertical: 10,
},
});
72 changes: 72 additions & 0 deletions packages/core/src/ActionSheet/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
ActionSheet 动作面板
---

该组件提供了一种动作面板, 底部缓缓出现

## 基础示例

```jsx
import { Fragment, useState } from 'react';
import { ActionSheet, Button,ActionSheetItem } from '@uiw/react-native';
function Demo() {
const [visible, setVisible] = useState(false)
return (
<Fragment>
<Button onPress={()=>setVisible(true)}>打开 ActionSheet</Button>
<ActionSheet
visible={visible}
>
<ActionSheetItem onPress={()=>console.log('按钮一')}>按钮一</ActionSheetItem>
<ActionSheetItem onPress={()=>console.log('按钮二')}>按钮二</ActionSheetItem>
</ActionSheet>
</Fragment>
);
}
```

## 弹层关闭 && 自定义取消文本

```jsx
import { Fragment, useState } from 'react';
import { ActionSheet, Button,ActionSheetItem } from '@uiw/react-native';
function Demo() {
const [visible, setVisible] = useState(false)
return (
<Fragment>
<Button onPress={()=>setVisible(true)}>打开 ActionSheet</Button>
<ActionSheet
visible={visible}
onCancel={true}
cancelText='取消'
>
<ActionSheetItem onPress={()=>console.log('按钮一')}>按钮一</ActionSheetItem>
<ActionSheetItem onPress={()=>console.log('按钮二')}>按钮二</ActionSheetItem>
</ActionSheet>
</Fragment>
);
}
```

## Props

```ts
import { ModalProps } from 'react-native';

export interface ActionSheetProps extends ModalProps {
/** 点击蒙层是否关闭 */
onCancel?: Boolean,
/** 是否展示元素 */
visible: Boolean,
/** 取消的文本 */
cancelText?: React.ReactNode
}
```

## ActionSheetItem Props

```ts
export interface ActionSheetProps extends ModalProps {
/** 点击 Item 触发的事件 */
onPress?: ((event: GestureResponderEvent) => void),
}
```
153 changes: 153 additions & 0 deletions packages/core/src/ActionSheet/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import React from 'react';
import { View, Dimensions, StyleSheet, Text, TouchableOpacity, Modal, ModalProps, Animated } from 'react-native';
import Item from './item'
export { default as ActionSheetItem } from './item';

let MainWidth = Dimensions.get('window').width;
let MainHeight = Dimensions.get('window').height;
export interface ActionSheetProps extends ModalProps {
/** 点击蒙层是否关闭 */
onCancel?: Boolean,
/** 取消的文本 */
cancelText?: React.ReactNode
}

interface ActionSheetState {
animatedHeight: number,
stateVisible: boolean
}

export default class ActionSheet extends React.Component<ActionSheetProps, ActionSheetState> {
private fadeAnim: Animated.Value = new Animated.Value(0);
private animatedRef: React.RefObject<View> = React.createRef()
constructor(props: ActionSheetProps) {
super(props)
this.state = {
animatedHeight: 0,
stateVisible: false
}
}

onClose = () => {
Animated.timing(this.fadeAnim, {
toValue: 0,
duration: 150,
useNativeDriver: true,
}).start(({ finished }) => {
this.setState({ stateVisible: false })
});
}
UNSAFE_componentWillReceiveProps(nextProps: ActionSheetProps) {
if (nextProps.visible) {
this.setState({ stateVisible: true })
Animated.timing(this.fadeAnim, {
toValue: 0,
duration: 0,
useNativeDriver: true,
}).start(({ finished }) => {
this.animatedRef.current &&
this.animatedRef.current.measure((_frameOffsetX, _frameOffsetY, _width, _height, pageOffsetX, pageOffsetY) => {
this.setState({ animatedHeight: _height }, () => {
Animated.timing(this.fadeAnim, {
toValue: -_height,
duration: 150,
useNativeDriver: true,
}).start();
})
})
});
}else {
this.onClose()
}
}
render() {
const { children, visible, cancelText = '取消', onCancel, ...other } = this.props
const { stateVisible } = this.state
if(!stateVisible) {
return null
}
return (
<Modal
animationType="fade" // slide none fade
transparent={true}
visible={stateVisible}
onRequestClose={this.onClose}
{...other}
>

<TouchableOpacity activeOpacity={1} style={[styles.position, styles.spread]} onPress={()=>onCancel&&this.onClose()}>
<Animated.View style={[styles.spread, styles.backdrop]}>
</Animated.View>
</TouchableOpacity>
<Animated.View
style={[
styles.actionSheet,
{ bottom: -this.state.animatedHeight, transform: [{ translateY: this.fadeAnim }] }
]}
ref={this.animatedRef}
>
{
React.Children.toArray(children).map((item, index) => (<View key={index}>
{index !== 0 && <View style={styles.actionSheetItemDivider} />}{item}
</View>))
}
<View style={styles.divider} />
{typeof cancelText !== 'object' ? <TouchableOpacity activeOpacity={1} onPress={this.onClose}>
<View style={styles.actionSheetItem}>
<Text style={styles.actionSheetItemText}>{cancelText}</Text>
</View>
</TouchableOpacity> : <View>{cancelText}</View>
}
</Animated.View>
</Modal>
);
}
}

const styles = StyleSheet.create({
position: {
position: 'absolute',
backgroundColor: 'transparent',
top: 0,
bottom: 0,
left: 0,
right: 0,
zIndex: 9998,
},
backdrop: {
backgroundColor: '#000',
opacity: .2
},
spread: {
width: MainWidth,
height: MainHeight
},
actionSheet: {
width: MainWidth,
position: 'absolute',
left: 0,
right: 0,
backgroundColor: '#fff',
zIndex: 9999
},
divider: {
backgroundColor: 'rgba(197,217,232,.3)',
width: MainWidth,
height: 6
},
actionSheetItemDivider: {
borderBottomColor: 'rgba(197,217,232,.3)',
borderBottomWidth: 2,
width: MainWidth,
},
actionSheetItem: {
width: MainWidth,
height: 50,
justifyContent: 'center',
alignItems: 'center',
},
actionSheetItemText: {
fontSize: 20,
fontWeight: '400',
}
});
38 changes: 38 additions & 0 deletions packages/core/src/ActionSheet/item.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React from 'react';
import { View, Dimensions, StyleSheet, Text,TouchableOpacity, GestureResponderEvent } from 'react-native';

let MainWidth = Dimensions.get('window').width;
export interface ActionSheetItemProps {
onPress?: ((event: GestureResponderEvent) => void),
}

export interface ActionSheetItemState {

}

export default class ActionSheetItem extends React.Component<ActionSheetItemProps, ActionSheetItemState> {

render() {
const { onPress=()=>{}, children } = this.props
return (
<TouchableOpacity activeOpacity={1} onPress={onPress}>
<View style={styles.actionSheetItem} >
<Text style={styles.actionSheetItemText}>{children}</Text>
</View>
</TouchableOpacity>
);
}
}

const styles = StyleSheet.create({
actionSheetItem: {
width: MainWidth,
height: 50,
justifyContent: 'center',
alignItems: 'center',
},
actionSheetItemText: {
fontSize: 20,
fontWeight: '400',
}
});
2 changes: 2 additions & 0 deletions packages/core/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ export * from './Tooltip';
export { default as CardCollapse } from './CardCollapse';
export * from './CardCollapse';

export { default as ActionSheet } from './ActionSheet';
export * from './ActionSheet';
/**
* Typography
*/
Expand Down
11 changes: 11 additions & 0 deletions website/src/pages/components/actionSheet/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import Markdown, { importAll } from '../../../component/Markdown';

export default class Page extends Markdown {
path = '/packages/core/src/ActionSheet/README.md';
getMarkdown = async () => {
const md = await import('@uiw/react-native/lib/ActionSheet/README.md');
// 支持 markdown 中,相对于当前 index.tsx 相对路径引入图片资源
importAll((require as any).context('./', true, /\.(png|gif|jpg|svg)$/), this.imageFiles);
return md.default || md;
};
}
1 change: 1 addition & 0 deletions website/src/routes/menus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export const componentMenus: MenuData[] = [
{ path: '/components/transitionImage', name: 'TransitionImage 图片过渡' },
{ path: '/components/progress', name: 'Progress 进度条' },
{ path: '/components/tooltip', name: 'Tooltip 工具提示' },
{ path: '/components/actionSheet', name: 'ActionSheet 动作面板' },
{ divider: true, name: '其它' },
{ href: 'https://github.com/uiwjs/react-native-alipay', name: 'Alipay 支付宝', target: '__blank' },
{
Expand Down
3 changes: 3 additions & 0 deletions website/src/routes/router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -211,4 +211,7 @@ export const getRouterData = {
'/components/cardcollapse': {
component: dynamicWrapper([], () => import('../pages/components/cardcollapse')),
},
'/components/actionSheet': {
component: dynamicWrapper([], () => import('../pages/components/actionSheet')),
},
};

0 comments on commit 38fae82

Please sign in to comment.