Skip to content

Typescript/stack aggregator #1339

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 10 commits into from
Jun 8, 2021
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
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
import _ from 'lodash';
import React, {Component} from 'react';
import {ScrollView} from 'react-native';
import {/* Colors, Typography, */View, Text, Button, StackAggregator} from 'react-native-ui-lib'; //eslint-disable-line
import {View, Text, Button, ButtonSize, StackAggregator} from 'react-native-ui-lib';


const contents = [
'Lorem Ipsum is simply dummy text of the printing and typesetting industry.',
'Lorem Ipsum is simply dummy text of the printing and typesetting industry.',
'Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum is simply dummy text of the printing and typesetting industry.',
'Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum is simply dummy text of the printing and typesetting industry.'
]
];

export default class StackAggregatorScreen extends Component {

onItemPress = (index) => {
onItemPress = (index: number) => {
console.warn('item pressed: ', index);
}

onPress = (index) => {
onPress = (index: number) => {
console.warn('item\'s button pressed: ', index);
}

renderItem = (item, index) => {
renderItem = (_: string, index: number) => {
return (
<View key={index} center padding-12>
<Button label={`${index}`} marginB-10 size={'small'} onPress={() => this.onPress(index)}/>
<Button label={`${index}`} marginB-10 size={ButtonSize.small} onPress={() => this.onPress(index)}/>
<Text>{contents[index]}</Text>
</View>
);
Expand Down
2 changes: 1 addition & 1 deletion generatedTypes/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export {default as Constants} from './helpers/Constants';
export {default as View, ViewPropTypes, ViewProps} from './components/view';
export {default as Text, TextPropTypes, TextProps} from './components/text';
export {default as TouchableOpacity, TouchableOpacityProps} from './components/touchableOpacity';
export {default as Button, ButtonPropTypes, ButtonProps} from './components/button';
export {default as Button, ButtonPropTypes, ButtonSize, ButtonProps} from './components/button';
export {default as Checkbox, CheckboxPropTypes, CheckboxProps} from './components/checkbox';
export {default as Chip, ChipPropTypes, ChipProps} from './components/chip';
export {default as Drawer, DrawerProps, DrawerItemProps} from './components/drawer';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,108 +1,115 @@
import _ from 'lodash';
import PropTypes from 'prop-types';
import React from 'react';
import {StyleSheet, Animated, Easing, LayoutAnimation} from 'react-native';
import React, {PureComponent} from 'react';
import {StyleSheet, Animated, Easing, LayoutAnimation, StyleProp, ViewStyle, LayoutChangeEvent} from 'react-native';
import {Constants} from '../../helpers';
import {Colors} from '../../style';
import {PureBaseComponent} from '../../commons';
import View from '../view';
import View, {ViewProps} from '../view';
import TouchableOpacity from '../touchableOpacity';
import Button from '../button';
import Button, {ButtonSize, ButtonProps} from '../button';
import Card from '../card';
import {asBaseComponent} from '../../commons/new';

const PEEP = 8;
const DURATION = 300;
const MARGIN_BOTTOM = 24;
const buttonStartValue = 0.8;
const icon = require('./assets/arrow-down.png');

/**
* @description: Stack aggregator component
* @modifiers: margin, padding
* @example: https://github.com/wix/react-native-ui-lib/blob/master/demo/src/screens/componentScreens/StackAggregatorScreen.js
* @gif: https://github.com/wix/react-native-ui-lib/blob/master/demo/showcase/StackAggregator/StackAggregator.gif?raw=true
*/
export default class StackAggregator extends PureBaseComponent {
static displayName = 'StackAggregator';

static propTypes = {
/**
export type StackAggregatorProps = ViewProps & {
/**
* The initial state of the stack
*/
collapsed: PropTypes.bool,
collapsed: boolean;
/**
* Component Children
*/
children: JSX.Element | JSX.Element[]
/**
* The container style
*/
containerStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.number, PropTypes.array]),
containerStyle?: StyleProp<ViewStyle>;
/**
* The content container style
*/
contentContainerStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.number, PropTypes.array]),
contentContainerStyle?: StyleProp<ViewStyle>;
/**
* The items border radius
*/
itemBorderRadius: PropTypes.number,
itemBorderRadius?: number;
/**
* Props passed to the 'show less' button
*/
buttonProps: PropTypes.object,
buttonProps?: ButtonProps;
/**
* A callback for item press
*/
onItemPress: PropTypes.func,
onItemPress?: (index: number) => void;
/**
* A callback for collapse state will change (value is future collapsed state)
*/
onCollapseWillChange: PropTypes.func,
onCollapseWillChange?: (changed: boolean) => void;
/**
* A callback for collapse state change (value is collapsed state)
*/
onCollapseChanged: PropTypes.func,
* A callback for collapse state change (value is collapsed state)
*/
onCollapseChanged?: (changed: boolean) => void;
/**
* A setting that disables pressability on cards
*/
disablePresses: PropTypes.boolean
}
disablePresses?: boolean;
};


type State = {
collapsed: boolean;
firstItemHeight?: number;
};

/**
* @description: Stack aggregator component
* @modifiers: margin, padding
* @example: https://github.com/wix/react-native-ui-lib/blob/master/demo/src/screens/componentScreens/StackAggregatorScreen.js
*/
class StackAggregator extends PureComponent<StackAggregatorProps, State> {
static displayName = 'StackAggregator';

animatedScale: Animated.Value;
animatedOpacity: any;
animatedContentOpacity: any;
itemsCount = React.Children.count(this.props.children);
easeOut = Easing.bezier(0, 0, 0.58, 1);
animatedScaleArray: Animated.Value[];

static defaultProps = {
disablePresses: false,
collapsed: true,
itemBorderRadius: 0
};

constructor(props) {
constructor(props: StackAggregatorProps) {
super(props);

this.state = {
collapsed: props.collapsed,
firstItemHeight: undefined
};

this.itemsCount = React.Children.count(props.children);
this.easeOut = Easing.bezier(0, 0, 0.58, 1);
this.animatedScale = new Animated.Value(this.state.collapsed ? buttonStartValue : 1);
this.animatedOpacity = new Animated.Value(this.state.collapsed ? buttonStartValue : 1);
this.animatedScaleArray = this.getAnimatedScales();
this.animatedContentOpacity = new Animated.Value(this.state.collapsed ? 0 : 1);
this.animatedScaleArray = this.getAnimatedScales();
}

componentDidUpdate(_prevProps, prevState) {
if (prevState.collapsed !== this.state.collapsed) {
componentDidUpdate(_prevProps: StackAggregatorProps, prevState: State) {
if (prevState.collapsed !== this.state?.collapsed) {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
}
}

generateStyles() {
this.styles = createStyles(this.getThemeProps());
}

getAnimatedScales() {
getAnimatedScales = (): Animated.Value[] => {
return React.Children.map(this.props.children, (_item, index) => {
return new Animated.Value(this.getItemScale(index));
});
}

getItemScale(index) {
getItemScale = (index: number) => {
if (this.state.collapsed) {
if (index === this.itemsCount - 2) {
return 0.95;
Expand All @@ -116,12 +123,12 @@ export default class StackAggregator extends PureBaseComponent {

animate = async () => {
return Promise.all([this.animateValues(), this.animateCards()]);
}
};

animateValues() {
const {collapsed} = this.state;
const newValue = collapsed ? buttonStartValue : 1;
return new Promise((resolve) => {
return new Promise(resolve => {
Animated.parallel([
Animated.timing(this.animatedOpacity, {
duration: DURATION,
Expand All @@ -144,13 +151,13 @@ export default class StackAggregator extends PureBaseComponent {
});
}

animateCards() {
animateCards() {
const promises = [];
for (let index = 0; index < this.itemsCount; index++) {
const newScale = this.getItemScale(index);

promises.push(
new Promise((resolve) => {
new Promise(resolve => {
Animated.timing(this.animatedScaleArray[index], {
toValue: Number(newScale),
easing: this.easeOut,
Expand All @@ -173,7 +180,7 @@ export default class StackAggregator extends PureBaseComponent {
this.animate();
}
});
}
};

open = () => {
this.setState({collapsed: false}, async () => {
Expand All @@ -185,9 +192,9 @@ export default class StackAggregator extends PureBaseComponent {
this.animate();
}
});
}
};

getTop(index) {
getTop(index: number) {
let start = 0;

if (index === this.itemsCount - 2) {
Expand All @@ -200,7 +207,7 @@ export default class StackAggregator extends PureBaseComponent {
return start;
}

getStyle(index) {
getStyle(index: number): StyleProp<ViewStyle> {
const {collapsed} = this.state;
const top = this.getTop(index);

Expand All @@ -216,19 +223,19 @@ export default class StackAggregator extends PureBaseComponent {
};
}

onLayout = event => {
onLayout = (event: LayoutChangeEvent) => {
const height = event.nativeEvent.layout.height;

if (height) {
this.setState({firstItemHeight: height});
}
};

onItemPress = index => {
onItemPress = (index: number) => {
_.invoke(this.props, 'onItemPress', index);
};

renderItem = (item, index) => {
renderItem = (item: JSX.Element | JSX.Element[], index: number) => {
const {contentContainerStyle, itemBorderRadius} = this.props;
const {firstItemHeight, collapsed} = this.state;

Expand All @@ -237,7 +244,7 @@ export default class StackAggregator extends PureBaseComponent {
key={index}
onLayout={index === 0 ? this.onLayout : undefined}
style={[
Constants.isIOS && this.styles.containerShadow,
Constants.isIOS && styles.containerShadow,
this.getStyle(index),
{
borderRadius: Constants.isIOS ? itemBorderRadius : undefined,
Expand All @@ -251,8 +258,8 @@ export default class StackAggregator extends PureBaseComponent {
collapsable={false}
>
<Card
style={[contentContainerStyle, this.styles.card]}
onPress={this.props.disablePresses ? false : () => this.onItemPress(index)}
style={[contentContainerStyle, styles.card]}
onPress={() => this.props.disablePresses && this.onItemPress(index)}
borderRadius={itemBorderRadius}
elevation={5}
>
Expand Down Expand Up @@ -283,7 +290,7 @@ export default class StackAggregator extends PureBaseComponent {
label={'Show less'}
iconSource={icon}
link
size={'small'}
size={ButtonSize.small}
{...buttonProps}
marginH-24
marginB-20
Expand All @@ -300,7 +307,7 @@ export default class StackAggregator extends PureBaseComponent {
onPress={this.open}
activeOpacity={1}
style={[
this.styles.touchable,
styles.touchable,
{
height: firstItemHeight ? firstItemHeight + PEEP * 2 : undefined,
zIndex: this.itemsCount
Expand All @@ -314,22 +321,22 @@ export default class StackAggregator extends PureBaseComponent {
}
}

function createStyles() {
return StyleSheet.create({
touchable: {
position: 'absolute',
width: '100%'
},
containerShadow: {
backgroundColor: Colors.white,
shadowColor: Colors.dark40,
shadowOpacity: 0.25,
shadowRadius: 12,
shadowOffset: {height: 5, width: 0}
},
card: {
overflow: 'hidden',
flexShrink: 1
}
});
}
const styles = StyleSheet.create({
touchable: {
position: 'absolute',
width: '100%'
},
containerShadow: {
backgroundColor: Colors.white,
shadowColor: Colors.dark40,
shadowOpacity: 0.25,
shadowRadius: 12,
shadowOffset: {height: 5, width: 0}
},
card: {
overflow: 'hidden',
flexShrink: 1
}
});

export default asBaseComponent<StackAggregatorProps>(StackAggregator);
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export {default as Modal, ModalProps, ModalTopBarProps} from './components/modal
export {default as PanGestureView, PanGestureViewProps} from './components/panningViews/panGestureView';
export {default as PanningContext} from './components/panningViews/panningContext';
export {default as asPanViewConsumer} from './components/panningViews/asPanViewConsumer';
export {default as StackAggregator, StackAggregatorProps} from './components/stackAggregator';
export {
default as PanningProvider,
PanningDirections,
Expand All @@ -72,7 +73,7 @@ export {
ActionSheet, ConnectionStatusBar, ChipsInput,
FeatureHighlight, BaseInput, TextArea, TextField, MaskedInput, ListItem, Picker,
PickerProps, ProgressBar, Slider, GradientSlider, ColorSliderGroup, Stepper,
TagsInput, SharedTransition, StackAggregator, Toast, WheelPickerDialog, Assets,
TagsInput, SharedTransition, Toast, WheelPickerDialog, Assets,
BaseComponent, PureBaseComponent, UIComponent, forwardRef, AvatarHelper,
LogService, LoaderScreen, StateScreen, WheelPicker, WheelPickerProps
} from '../typings';
Loading