Skip to content

Commit

Permalink
Merge branch 'release/4.3.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
Slavko committed Mar 2, 2021
2 parents 68ec757 + 6f8e2ea commit c84f078
Show file tree
Hide file tree
Showing 17 changed files with 988 additions and 4 deletions.
5 changes: 5 additions & 0 deletions components/Icon/assets/checkbox-rectangle-off.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions components/Icon/assets/checkbox-rectangle-on.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions components/Icon/assets/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import camSwitch from './cam-switch.svg';
import cart from './cart.svg';
import checkboxOff from './checkbox-off.svg';
import checkboxOn from './checkbox-on.svg';
import checkbocRectangleOff from './checkbox-rectangle-off';
import checkbocRectangleOn from './checkbox-rectangle-on';
import clearText from './clear-text.svg';
import close from './close.svg';
import comment from './comment.svg';
Expand Down Expand Up @@ -111,6 +113,8 @@ export const defaultConfig = [
{ name: 'cart', icon: cart },
{ name: 'checkbox-off', icon: checkboxOff },
{ name: 'checkbox-on', icon: checkboxOn },
{ name: 'checkbox-rectangle-off', icon: checkbocRectangleOff },
{ name: 'checkbox-rectangle-on', icon: checkbocRectangleOn },
{ name: 'clear-text', icon: clearText },
{ name: 'close', icon: close },
{ name: 'comment', icon: comment },
Expand Down
130 changes: 130 additions & 0 deletions components/InlineDropDownMenu/InlineDropDownMenu.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import React, { PureComponent } from 'react';
import autoBindReact from 'auto-bind/react';
import { FlatList, Animated } from 'react-native';
import _ from 'lodash';
import PropTypes from 'prop-types';
import { connectStyle } from '@shoutem/theme';
import { TouchableOpacity } from '../TouchableOpacity';
import { View } from '../View';
import { Caption, Text } from '../Text';
import { Icon } from '../Icon';
import { InlineDropDownMenuItem } from './InlineDropDownMenuItem';

const AnimatedIcon = Animated.createAnimatedComponent(Icon);

const optionShape = PropTypes.shape({
title: PropTypes.string.isRequired,
key: PropTypes.string.isRequired,
});

class InlineDropDownMenu extends PureComponent {
static propTypes = {
heading: PropTypes.string,
selectedDescriptor: PropTypes.string,
options: PropTypes.arrayOf(optionShape).isRequired,
onOptionSelected: PropTypes.func,
selectedOption: optionShape,
};

constructor(props) {
super(props);

autoBindReact(this);

this.dropDownIconValue = new Animated.Value(0);

this.state = {
collapsed: false,
};
}

handleToggleMenuPress() {
const { collapsed } = this.state;

const toValue = collapsed ? 0 : 1;

this.setState(
{ collapsed: !collapsed },
() => Animated.timing(
this.dropDownIconValue,
{
toValue,
useNativeDriver: true,
duration: 300,
}
).start());
}

handleOptionPress(option) {
const { onOptionSelected } = this.props;

if (onOptionSelected) {
onOptionSelected(option);
}

this.handleToggleMenuPress();
}

renderOption({ item, index }) {
const { selectedOption, selectedDescriptor } = this.props;

const isSelected = selectedOption.key === item.key;

return (
<InlineDropDownMenuItem
item={item}
isSelected={isSelected}
index={index}
selectedDescriptor={selectedDescriptor}
onItemPressed={this.handleOptionPress}
/>
)
}

render() {
const {
style,
heading,
selectedOption,
options,
} = this.props;
const { collapsed } = this.state;

return (
<View>
<TouchableOpacity style={style.container} onPress={this.handleToggleMenuPress}>
<Caption styleName="muted md-gutter-bottom">{heading}</Caption>
<View styleName="space-between horizontal v-center">
<Text>{selectedOption?.title}</Text>
<AnimatedIcon
name="drop-down"
styleName="md-gutter-left"
style={{
...style.icon,
transform: [{
rotate: this.dropDownIconValue.interpolate({
inputRange: [0, 1],
outputRange: ['0deg', '180deg']
})
}]
}}
/>
</View>
</TouchableOpacity>
{collapsed && (
<FlatList
data={options}
renderItem={this.renderOption}
contentContainerStyle={style.list}
/>
)}
</View>
);
}
}

const StyledComponent = connectStyle('shoutem.ui.InlineDropDownMenu')(
InlineDropDownMenu,
);

export { StyledComponent as InlineDropDownMenu };
85 changes: 85 additions & 0 deletions components/InlineDropDownMenu/InlineDropDownMenuItem.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import React, { PureComponent } from 'react';
import autoBindReact from 'auto-bind/react';
import { Animated, Dimensions } from 'react-native';
import _ from 'lodash';
import PropTypes from 'prop-types';
import { connectStyle } from '@shoutem/theme';
import { TouchableOpacity } from '../TouchableOpacity';
import { Text } from '../Text';

const window = Dimensions.get('window');
const AnimatedTouchable = Animated.createAnimatedComponent(TouchableOpacity);

class InlineDropDownMenuItem extends PureComponent {
static propTypes = {
item: PropTypes.object,
index: PropTypes.number,
selectedDescriptor: PropTypes.string,
onItemPressed: PropTypes.func,
isSelected: PropTypes.bool,
};

constructor(props) {
super(props);

autoBindReact(this);

this.animatedValue = new Animated.Value(0);
}

componentDidMount() {
const { index } = this.props;

Animated.timing(
this.animatedValue,
{
toValue: 1,
useNativeDriver: true,
duration: 300 + index * 15,
}
).start();
}

handlePress() {
const { onItemPressed, item } = this.props;

if (onItemPressed) {
onItemPressed(item);
}
}

render() {
const { isSelected, selectedDescriptor, item, style } = this.props;

const resolvedText = isSelected ? `${item.title} (${selectedDescriptor})` : item.title;
const textStyle = isSelected ? 'muted' : '';

return (
<AnimatedTouchable
style={[
style.container,
{
transform: [
{
translateX: this.animatedValue.interpolate({
inputRange: [0, 1],
outputRange: [window.width, 0],
})
}
],
}
]}
disabled={isSelected}
onPress={this.handlePress}
>
<Text styleName={textStyle}>{resolvedText}</Text>
</AnimatedTouchable>
);
}
}

const StyledComponent = connectStyle('shoutem.ui.InlineDropDownMenuItem')(
InlineDropDownMenuItem,
);

export { StyledComponent as InlineDropDownMenuItem };
2 changes: 2 additions & 0 deletions components/InlineDropDownMenu/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { InlineDropDownMenu } from './InlineDropDownMenu';
export { InlineDropDownMenuItem } from './InlineDropDownMenuItem';
64 changes: 64 additions & 0 deletions components/TabMenu/TabMenu.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import autoBindReact from 'auto-bind/react';
import _ from 'lodash';
import { ScrollView, LayoutAnimation } from 'react-native';
import { connectStyle } from '@shoutem/theme';
import { optionShape } from './const';
import { TabMenuItem } from './TabMenuItem';

class TabMenu extends PureComponent {
static propTypes = {
options: PropTypes.arrayOf(optionShape).isRequired,
onOptionSelected: PropTypes.func,
selectedOption: optionShape,
style: PropTypes.object,
};

constructor(props) {
super(props);

autoBindReact(this);
}

handleOptionSelected(option) {
const { onOptionSelected } = this.props;

LayoutAnimation.easeInEaseOut();
onOptionSelected(option);
}

renderOption(option) {
const { selectedOption } = this.props;

const isSelected = selectedOption && option.title === selectedOption.title;

return (
<TabMenuItem
key={option.title}
isSelected={isSelected}
item={option}
onItemPressed={this.handleOptionSelected}
/>
);
}

render() {
const { style, options } = this.props;

return (
<ScrollView
horizontal
contentContainerStyle={style.container}
showsHorizontalScrollIndicator={false}
style={style.list}
>
{_.map(options, this.renderOption)}
</ScrollView>
);
}
}

const StyledTabMenu = connectStyle('shoutem.ui.TabMenu')(TabMenu);

export { StyledTabMenu as TabMenu };
65 changes: 65 additions & 0 deletions components/TabMenu/TabMenuItem.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import React, { PureComponent } from 'react';
import { LayoutAnimation } from 'react-native';
import PropTypes from 'prop-types';
import autoBindReact from 'auto-bind/react';
import _ from 'lodash';
import { connectStyle } from '@shoutem/theme';
import { Text } from '../Text';
import { View } from '../View';
import { TouchableOpacity } from '../TouchableOpacity';
import { optionShape } from './const';

class TabMenuItem extends PureComponent {
static propTypes = {
item: optionShape,
onItemPressed: PropTypes.any,
isSelected: PropTypes.bool,
style: PropTypes.object,
};

constructor(props) {
super(props);

autoBindReact(this);

this.state = {
baseWidth: 0,
};
}

handleItemPressed() {
const { onItemPressed, item } = this.props;

onItemPressed(item);
}

handleLayout({ nativeEvent: { layout: { width } } }) {

LayoutAnimation.easeInEaseOut();
this.setState({ baseWidth: width });
}

render() {
const { style, isSelected, item } = this.props;
const { baseWidth } = this.state;

return (
<TouchableOpacity
onPress={this.handleItemPressed}
styleName="vertical h-center"
>
<Text
style={[style.text, isSelected && style.selectedText]}
onLayout={this.handleLayout}
>
{item.title}
</Text>
{isSelected && <View style={[style.tabulator, { width: baseWidth }]} />}
</TouchableOpacity>
);
}
}

const StyledTabMenuItem = connectStyle('shoutem.ui.TabMenuItem')(TabMenuItem);

export { StyledTabMenuItem as TabMenuItem };
6 changes: 6 additions & 0 deletions components/TabMenu/const.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import PropTypes from 'prop-types';

export const optionShape = PropTypes.shape({
title: PropTypes.string,
value: PropTypes.any,
});
1 change: 1 addition & 0 deletions components/TabMenu/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { TabMenu } from './TabMenu';
Loading

0 comments on commit c84f078

Please sign in to comment.