Skip to content

Commit

Permalink
Added New Component: Speed dial (react-native-elements#2896)
Browse files Browse the repository at this point in the history
* Docs Fixed

* Added SpeedDial

* Added SpeedDial

* Docs Update

* Fixed

* Docs

* Update SpeedDial.tsx

* Fixed

* Changed Props

* Docs

* Docs

* Fixed Strict Errors

* Fixed
  • Loading branch information
arpitBhalla authored Apr 4, 2021
1 parent 49f97d8 commit 7fdec69
Show file tree
Hide file tree
Showing 13 changed files with 431 additions and 8 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,10 @@ import { Button } from 'react-native-elements';
- [x] [SearchBar](https://reactnativeelements.com/docs/searchbar)
- [x] [Slider](https://reactnativeelements.com/docs/slider)
- [x] [Social Icons / Social Icon Buttons](https://reactnativeelements.com/docs/social_icon)
- [x] [Speed Dial](https://reactnativeelements.com/docs/speeddial)
- [x] [Switch](https://reactnativeelements.com/docs/switch)
- [x] [Tile](https://reactnativeelements.com/docs/tile)
- [x] [Tooltip](https://reactnativeelements.com/docs/tooltip)
- [x] [Switch](https://reactnativeelements.com/docs/switch)

## React Native Web support

Expand Down
148 changes: 148 additions & 0 deletions src/buttons/SpeedDial.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import React from 'react';
import {
Text,
View,
Animated,
StyleSheet,
SafeAreaView,
TouchableWithoutFeedback,
} from 'react-native';
import FAB, { FABProps } from './FAB';
import { withTheme } from '../config';
import { IconNode } from '../icons/Icon';
import Color from 'color';
import { RneFunctionComponent } from '../helpers';

export type SpeedDialActionProps = Omit<FABProps, 'size'>;

const SpeedDialAction: RneFunctionComponent<SpeedDialActionProps> = withTheme(
({ title, titleStyle, ...actionProps }) => {
return (
<View style={styles.action}>
{title && <Text style={[styles.title, titleStyle]}>{title}</Text>}
<FAB {...actionProps} size="small" style={[actionProps.style]} />
</View>
);
},
'SpeedDial.Action'
);

export type SpeedDialProps = {
isOpen: boolean;
onOpen: () => void;
onClose: () => void;
openIcon?: IconNode;
children?: React.ReactChild[];
transitionDuration?: number;
} & FABProps;

const SpeedDial: RneFunctionComponent<SpeedDialProps> = ({
theme,
isOpen,
onOpen = () => {},
onClose = () => {},
icon,
openIcon,
children,
transitionDuration = 150,
style,
...props
}) => {
const animations = React.useRef<Animated.Value[]>(
[...new Array(React.Children.count(children))].map(
() => new Animated.Value(Number(isOpen))
)
);

React.useEffect(() => {
Animated.stagger(
50,
animations.current
.map((animation) =>
Animated.timing(animation, {
toValue: Number(isOpen),
duration: transitionDuration,
useNativeDriver: true,
})
)
[isOpen ? 'reverse' : 'sort']()
).start();
}, [isOpen, animations, children, transitionDuration]);

return (
<View style={[styles.container, style]}>
<TouchableWithoutFeedback onPress={onClose}>
<Animated.View
style={[
StyleSheet.absoluteFillObject,
{
opacity: animations.current[0],
backgroundColor: Color(theme?.colors?.black)
.alpha(0.6)
.rgb()
.toString(),
},
]}
pointerEvents={isOpen ? 'auto' : 'none'}
/>
</TouchableWithoutFeedback>

<SafeAreaView pointerEvents="box-none" style={styles.safeArea}>
{React.Children.toArray(children).map((ChildAction, i: number) => (
<Animated.View
pointerEvents={isOpen ? 'auto' : 'none'}
key={i}
style={{
transform: [{ scale: animations.current[i] }],
opacity: animations.current[i],
}}
>
{ChildAction}
</Animated.View>
))}
<FAB
style={[styles.fab]}
icon={isOpen ? openIcon : icon}
{...props}
onPress={isOpen ? onClose : onOpen}
/>
</SafeAreaView>
</View>
);
};

const styles = StyleSheet.create({
safeArea: {
alignItems: 'flex-end',
},
container: {
...StyleSheet.absoluteFillObject,
justifyContent: 'flex-end',
},
fab: {
margin: 16,
marginTop: 0,
},
title: {
backgroundColor: 'white',
color: 'black',
borderRadius: 5,
paddingHorizontal: 12,
paddingVertical: 6,
marginVertical: 8,
marginHorizontal: 16,
elevation: 2,
},
action: {
marginBottom: 16,
marginRight: 24,
flexDirection: 'row',
justifyContent: 'flex-end',
alignItems: 'center',
},
});
export { SpeedDial };

export default Object.assign(withTheme(SpeedDial, 'SpeedDial'), {
Action: SpeedDialAction,
});
31 changes: 31 additions & 0 deletions src/buttons/__tests__/SpeedDial.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React from 'react';
import { SpeedDial } from '../SpeedDial';
import { shallow } from 'enzyme';
import toJson from 'enzyme-to-json';
import theme from '../../config/theme';

describe('Speed Dial Component', () => {
it('should render without issues', () => {
const app = shallow(
<SpeedDial
theme={theme}
open={true}
icon={{ name: 'edit', color: '#fff' }}
openIcon={{ name: 'close', color: '#fff' }}
>
<SpeedDial.Action
icon={{ name: 'add', color: '#fff' }}
title="Add"
onPress={() => console.log('Add Something')}
/>
<SpeedDial.Action
icon={{ name: 'delete', color: '#fff' }}
title="Delete"
onPress={() => console.log('Delete Something')}
/>
</SpeedDial>
);
expect(app.length).toBe(1);
expect(toJson(app)).toMatchSnapshot();
});
});
121 changes: 121 additions & 0 deletions src/buttons/__tests__/__snapshots__/SpeedDial.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Speed Dial Component should render without issues 1`] = `
<View
style={
Array [
Object {
"bottom": 0,
"justifyContent": "flex-end",
"left": 0,
"position": "absolute",
"right": 0,
"top": 0,
},
undefined,
]
}
>
<TouchableWithoutFeedback
onPress={[Function]}
>
<ForwardRef(AnimatedComponentWrapper)
pointerEvents="none"
style={
Array [
Object {
"bottom": 0,
"left": 0,
"position": "absolute",
"right": 0,
"top": 0,
},
Object {
"backgroundColor": "rgba(36, 36, 36, 0.6)",
"opacity": NaN,
},
]
}
/>
</TouchableWithoutFeedback>
<ForwardRef(SafeAreaView)
pointerEvents="box-none"
style={
Object {
"alignItems": "flex-end",
}
}
>
<ForwardRef(AnimatedComponentWrapper)
key="0"
pointerEvents="none"
style={
Object {
"opacity": NaN,
"transform": Array [
Object {
"scale": NaN,
},
],
}
}
>
<Component
icon={
Object {
"color": "#fff",
"name": "add",
}
}
key=".0"
onPress={[Function]}
title="Add"
/>
</ForwardRef(AnimatedComponentWrapper)>
<ForwardRef(AnimatedComponentWrapper)
key="1"
pointerEvents="none"
style={
Object {
"opacity": NaN,
"transform": Array [
Object {
"scale": NaN,
},
],
}
}
>
<Component
icon={
Object {
"color": "#fff",
"name": "delete",
}
}
key=".1"
onPress={[Function]}
title="Delete"
/>
</ForwardRef(AnimatedComponentWrapper)>
<Themed.FloatingActionButton
icon={
Object {
"color": "#fff",
"name": "edit",
}
}
onPress={[Function]}
open={true}
style={
Array [
Object {
"margin": 16,
"marginTop": 0,
},
]
}
/>
</ForwardRef(SafeAreaView)>
</View>
`;
2 changes: 1 addition & 1 deletion src/header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export type HeaderProps = ViewProps & {
leftContainerStyle?: StyleProp<ViewStyle>;
rightContainerStyle?: StyleProp<ViewStyle>;
children?: JSX.Element[];
elevated: boolean;
elevated?: boolean;
};

const Header: RneFunctionComponent<HeaderProps> = (props) => {
Expand Down
7 changes: 7 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ import Slider, { SliderProps } from './slider/Slider';
import ButtonGroup, { ButtonGroupProps } from './buttons/ButtonGroup';
import Image, { ImageProps } from './image/Image';
import FAB, { FABProps } from './buttons/FAB';
import SpeedDial, {
SpeedDialActionProps,
SpeedDialProps,
} from './buttons/SpeedDial';
// Productivity
import Card, { CardProps } from './card/Card';
import Tile, { TileProps } from './tile/Tile';
Expand Down Expand Up @@ -101,6 +105,7 @@ export {
makeStyles,
Image,
FAB,
SpeedDial,
};
export type {
AvatarProps,
Expand Down Expand Up @@ -137,5 +142,7 @@ export type {
Theme,
LinearProgressProps,
FABProps,
SpeedDialActionProps,
SpeedDialProps,
ThemeProps,
};
8 changes: 3 additions & 5 deletions website/docs/props/fab.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
> Also receives all [Button](https://reactnative.dev/docs/button#props) props
> Also receives all [Button](https://reactnativeelements.com/docs/button#props) props
- [`placement`](#placement)
- [`color`](#color)
Expand All @@ -12,7 +12,7 @@

### `placement`

FAB placement bottom, (optional) use [`style`](#style) in case of custom placement
FAB placement at bottom, (optional) use [`style`](#style) in case of custom placement

| Type | Default |
| :--------------: | :-----: |
Expand All @@ -22,8 +22,6 @@ FAB placement bottom, (optional) use [`style`](#style) in case of custom placeme

### `color`

Color of FAB

| Type | Default |
| :--------: | :---------------------: |
| color name | theme's secondary color |
Expand All @@ -32,7 +30,7 @@ Color of FAB

### `size`

Size for Extended FAB
Size of FAB

| Type | Default |
| :----------------: | :-----: |
Expand Down
Loading

0 comments on commit 7fdec69

Please sign in to comment.