Skip to content

fix(Accordion)添加Accordion手风琴组件 #588

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 6 additions & 8 deletions example/examples/lib2/ImagePicker/index.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
import React from 'react';
import {View, Text, StyleSheet} from 'react-native';
import { View, Text, StyleSheet } from 'react-native';
const ImagePicker = () => {
return (
<View style={styles.tree}>
return <View style={styles.tree}>
<Text>ImagePicker</Text>
</View>
);
</View>;
};
const styles = StyleSheet.create({
tree: {
paddingHorizontal: 10,
paddingVertical: 5,
backgroundColor: '#fff',
},
backgroundColor: '#fff'
}
});
export default ImagePicker;
export default ImagePicker;
2 changes: 1 addition & 1 deletion example/examples/lib2/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export {default as ImagePicker} from './ImagePicker';
export { default as ImagePicker } from './ImagePicker';
export * from './ImagePicker';
4 changes: 2 additions & 2 deletions example/examples/lib2/index.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export {default as ImagePicker} from './ImagePicker';
export * from './ImagePicker';
export { default as ImagePicker } from './ImagePicker';
export * from './ImagePicker';
10 changes: 9 additions & 1 deletion example/examples/src/routes.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {StackNavigationProp, StackNavigationOptions} from '@react-navigation/stack';
import { StackNavigationProp, StackNavigationOptions } from '@react-navigation/stack';

type ModalStackNavigation = StackNavigationProp<{}>;

Expand Down Expand Up @@ -498,4 +498,12 @@ export const stackPageData: Routes[] = [
description: '图片上传',
},
},
{
name: 'Accordion',
component: require('./routes/Accordion').default,
params: {
title: 'Accordion 手风琴',
description: '可以折叠/展开的内容区域。',
},
},
];
77 changes: 77 additions & 0 deletions example/examples/src/routes/Accordion/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import React, { Component } from 'react';
import { View, Image } from 'react-native';
import { Accordion, Text } from '@uiw/react-native';
import Layout, { Container } from '../../Layout';
import { ComProps } from '../../routes';
const { Header, Body, Card, Footer } = Layout;

export interface Accordion extends ComProps { }

const contents = [
{
title: <Text>Section 1</Text>,
content: (
<View>
<Text>Content of section 1</Text>
<Image source={{ uri: 'https://wx3.sinaimg.cn/mw690/4718260ely1gt2cg7t5udj23dw1wkhdu.jpg' }} style={{ height: 180 }} />
</View>
),
},
{
title: <Text>Section 2</Text>,
content: (
<View>
<Text>Content of section 2</Text>
<Image source={{ uri: 'https://wx1.sinaimg.cn/mw690/4718260ely1gt2cg5r9zij22yo1o0x6p.jpg' }} style={{ height: 180 }} />
</View>
),
},
{
title: <Text>Section 3</Text>,
content: (
<View>
<Text>Content of section 3</Text>
<Image source={{ uri: 'https://iknow-pic.cdn.bcebos.com/810a19d8bc3eb135828572d2ab1ea8d3fd1f441d' }} style={{ height: 180 }} />
</View>
),
},
];
export default class MenuDropdownView extends Component<Accordion> {
state = {
expanded: false,
top: 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>
<Card title="基础实例">
<Accordion sections={contents} />
</Card>
<Card title="是否可以展开多个.默认为是,当前为否">
<Accordion sections={contents} isMultiple={false} />
</Card>
<Card title="是否展示右侧图标,默认为是,当前为否">
<Accordion sections={contents} iconShow={false} />
</Card>
<Card title="设置右侧图标尺寸大小">
<Accordion sections={contents} iconSize={30} />
</Card>
<Card title="每行列表手风琴样式">
<Accordion sections={contents} accordionStyle={{ backgroundColor: '#3578e5' }} />
</Card>
<Card title="展开手风琴内容样式">
<Accordion sections={contents} contentStyle={{ backgroundColor: '#FFD21D' }} />
</Card>
</Body>
<Footer />
</Layout>
</Container>
);
}
}
61 changes: 61 additions & 0 deletions packages/core/src/Accordion/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
Accordion 手风琴组件
---
可以折叠/展开的内容区域。

### 基础示例

```jsx mdx:preview&background=#bebebe29
import React,{ Component } from "react"
import { View, Text,Image,Card } from 'react-native';
import { Accordion } from '@uiw/react-native';

const contents = [
{
title: <Text>Section 1</Text>,
content: (
<View>
<Text>Content of section 1</Text>
<Image source={{ uri: 'https://wx3.sinaimg.cn/mw690/4718260ely1gt2cg7t5udj23dw1wkhdu.jpg' }} style={{ height: 180 }} />
</View>
),
},
{
title: <Text>Section 2</Text>,
content: (
<View>
<Text>Content of section 2</Text>
<Image source={{ uri: 'https://wx1.sinaimg.cn/mw690/4718260ely1gt2cg5r9zij22yo1o0x6p.jpg' }} style={{ height: 180 }} />
</View>
),
},
{
title: <Text>Section 3</Text>,
content: (
<View>
<Text>Content of section 3</Text>
<Image source={{ uri: 'https://iknow-pic.cdn.bcebos.com/810a19d8bc3eb135828572d2ab1ea8d3fd1f441d' }} style={{ height: 180 }} />
</View>
),
},
];

function Demo() {
return (
<View style={{ marginTop: 50 }}>
<Accordion sections={contents} />
</View>
);
}
```

### Props

| 参数 | 说明 | 类型 | 默认值 |
|------|------|-----|------|
| `sections` | 自定义手风琴列表,通过`title`参数设置标题,通过`content`参数设置展示内容,通过`isOnPress`参数设置是否禁用 | JSX.Element | - |
| `isMultiple` | 是否同时展示多个内容| boolean | true |
| `accordionStyle` | 手风琴每行列表样式 | ViewStyle | - |
| `contentStyle` | 点击展开内容样式 | ViewStyle | - |
| `iconShow` | 是否展示图标 | boolean | true |
| `iconSize` | 设置图标尺寸 | number | - |

119 changes: 119 additions & 0 deletions packages/core/src/Accordion/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import React, { FC, useState, useRef } from 'react';
import { StyleSheet, View, TouchableOpacity, StyleProp, ViewStyle, LayoutAnimation, Animated } from 'react-native';
import { Theme } from '../theme';
import { useTheme } from '@shopify/restyle';
import Icon from '../Icon';

interface AccordionProps {
/** 自定义手风琴列表*/
sections: {
/** 列表标题内容*/
title: JSX.Element;
/** 展开内容*/
content: JSX.Element;
/** 是否可以点击,默认可以点击*/
isOnPress?: boolean;
}[];
/** 是否展示多个,默认展示多个*/
isMultiple?: boolean;
/** 手风琴每行列表样式 */
accordionStyle?: StyleProp<ViewStyle>;
/** 点击展开内容样式 */
contentStyle?: StyleProp<ViewStyle>;
/** 是否展示图标 */
iconShow?: boolean;
/** 图标源 */
customIcon?: string | JSX.Element;
/** 图标尺寸 */
iconSize?: number;
}

const Accordion: FC<AccordionProps> = (props) => {
const { sections, isMultiple = true, iconShow = true, iconSize = 18, accordionStyle, contentStyle } = props;
const [activeIndex, setActiveIndex] = useState<number[] | number>(isMultiple ? [] : -1);
const theme = useTheme<Theme>();
const styles = createStyles({
bgColor: theme.colors.mask,
headerColor: theme.colors.background,
borderColor: theme.colors.border,
});
const animatedController = useRef(new Animated.Value(0)).current;

const onPress = (index: number | never) => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
if (isMultiple) {
const currentIndex = Array.isArray(activeIndex) ? activeIndex.indexOf(index) : -1;
if (currentIndex > -1) {
const newActiveIndex = Array.isArray(activeIndex) ? [...activeIndex] : [];
if (currentIndex > -1) {
newActiveIndex.splice(currentIndex, 1);
}
setActiveIndex(newActiveIndex);
} else {
setActiveIndex(Array.isArray(activeIndex) ? [...activeIndex, index] : [index]);
}
} else {
setActiveIndex(activeIndex === index ? -1 : index);
}
Animated.timing(animatedController, {
toValue: activeIndex === index ? 0 : 1,
duration: 500,
useNativeDriver: true,
}).start();
};

const rotateZ = animatedController.interpolate({
inputRange: [0, 1],
outputRange: ['0deg', '90deg'],
});

return (
<View>
{sections.map((item, index) => (
<View key={index}>
<TouchableOpacity disabled={item?.isOnPress || false} activeOpacity={0.8} onPress={() => onPress(index)} style={[styles.header, accordionStyle]}>
<View style={styles.titleBy} key={index}>
{item.title}
{iconShow &&
<Animated.View style={{ transform: [{ rotateZ: activeIndex === index || (Array.isArray(activeIndex) && activeIndex.indexOf(index) > -1) ? rotateZ : '0deg' }] }}>
<Icon name="right" size={iconSize} color={theme.colors.border} />
</Animated.View>}
</View>
</TouchableOpacity>
{(isMultiple && Array.isArray(activeIndex) && activeIndex.indexOf(index) > -1 || !isMultiple && activeIndex === index) && <View
style={[styles.content, contentStyle]}>
{item.content}
</View>}
</View>
))}
</View>
)
}

type CreStyle = {
bgColor: string;
headerColor: string;
borderColor: string;
};

function createStyles({ bgColor, borderColor, headerColor }: CreStyle) {
return StyleSheet.create({
titleBy: {
flexDirection: 'row',
justifyContent: 'space-between',
},
header: {
borderBottomWidth: 1,
borderBottomColor: borderColor,
padding: 15,
backgroundColor: headerColor,
},
content: {
padding: 15,
backgroundColor: bgColor,
},
});
}

export default Accordion;

3 changes: 2 additions & 1 deletion packages/core/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,8 @@ export { default as ImageViewer } from './ImageViewer';
export * from './ImageViewer';
export { default as Form } from './Form';
export * from './Form';

export { default as Accordion } from './Accordion';
export * from './Accordion';
/**
* Typography
*/
Expand Down
6 changes: 6 additions & 0 deletions website/src/pages/components/accordion/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import Preview from 'src/component/Preview';
import md from '@uiw/react-native/README.md';

const Demo = () => <Preview {...md} path="/packages/core/src/Accordion/README.md" />;

export default Demo;
1 change: 1 addition & 0 deletions website/src/routes/menus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export const componentMenus: MenuData[] = [
{ path: '/components/swipeaction', name: 'SwipeAction 滑动操作组件' },
{ path: '/components/expandablesection', name: 'ExpandableSection 展开缩放组件' },
{ path: '/components/cardcollapse', name: 'CardCollapse 可折叠卡片列表' },
{ path: '/components/accordion', name: 'Accordion 可折叠/展开的内容区域' },
{ divider: true, name: 'Data Entry' },
{ path: '/components/form', name: 'Form 表单 🚧' },
{ path: '/components/checkbox', name: 'CheckBox 复选框' },
Expand Down
4 changes: 4 additions & 0 deletions website/src/routes/router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,10 @@ export const routeData = [
path: '/components/cardcollapse',
component: lazy(() => import('../pages/components/cardcollapse')),
},
{
path: '/components/accordion',
component: lazy(() => import('../pages/components/accordion')),
},
{
path: '/components/actionSheet',
component: lazy(() => import('../pages/components/actionSheet')),
Expand Down