diff --git a/components/Icon/assets/checkbox-rectangle-off.svg b/components/Icon/assets/checkbox-rectangle-off.svg new file mode 100644 index 00000000..ced67461 --- /dev/null +++ b/components/Icon/assets/checkbox-rectangle-off.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/components/Icon/assets/checkbox-rectangle-on.svg b/components/Icon/assets/checkbox-rectangle-on.svg new file mode 100644 index 00000000..eba3dc93 --- /dev/null +++ b/components/Icon/assets/checkbox-rectangle-on.svg @@ -0,0 +1,3 @@ + + + diff --git a/components/Icon/assets/index.js b/components/Icon/assets/index.js index 943803d7..617408b8 100644 --- a/components/Icon/assets/index.js +++ b/components/Icon/assets/index.js @@ -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'; @@ -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 }, diff --git a/components/InlineDropDownMenu/InlineDropDownMenu.js b/components/InlineDropDownMenu/InlineDropDownMenu.js new file mode 100644 index 00000000..27ac6677 --- /dev/null +++ b/components/InlineDropDownMenu/InlineDropDownMenu.js @@ -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 ( + + ) + } + + render() { + const { + style, + heading, + selectedOption, + options, + } = this.props; + const { collapsed } = this.state; + + return ( + + + {heading} + + {selectedOption?.title} + + + + {collapsed && ( + + )} + + ); + } +} + +const StyledComponent = connectStyle('shoutem.ui.InlineDropDownMenu')( + InlineDropDownMenu, +); + +export { StyledComponent as InlineDropDownMenu }; diff --git a/components/InlineDropDownMenu/InlineDropDownMenuItem.js b/components/InlineDropDownMenu/InlineDropDownMenuItem.js new file mode 100644 index 00000000..deadf676 --- /dev/null +++ b/components/InlineDropDownMenu/InlineDropDownMenuItem.js @@ -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 ( + + {resolvedText} + + ); + } +} + +const StyledComponent = connectStyle('shoutem.ui.InlineDropDownMenuItem')( + InlineDropDownMenuItem, +); + +export { StyledComponent as InlineDropDownMenuItem }; diff --git a/components/InlineDropDownMenu/index.js b/components/InlineDropDownMenu/index.js new file mode 100644 index 00000000..b95d8e64 --- /dev/null +++ b/components/InlineDropDownMenu/index.js @@ -0,0 +1,2 @@ +export { InlineDropDownMenu } from './InlineDropDownMenu'; +export { InlineDropDownMenuItem } from './InlineDropDownMenuItem'; diff --git a/components/TabMenu/TabMenu.js b/components/TabMenu/TabMenu.js new file mode 100644 index 00000000..cb08b9bc --- /dev/null +++ b/components/TabMenu/TabMenu.js @@ -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 ( + + ); + } + + render() { + const { style, options } = this.props; + + return ( + + {_.map(options, this.renderOption)} + + ); + } +} + +const StyledTabMenu = connectStyle('shoutem.ui.TabMenu')(TabMenu); + +export { StyledTabMenu as TabMenu }; diff --git a/components/TabMenu/TabMenuItem.js b/components/TabMenu/TabMenuItem.js new file mode 100644 index 00000000..55c9adc4 --- /dev/null +++ b/components/TabMenu/TabMenuItem.js @@ -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 ( + + + {item.title} + + {isSelected && } + + ); + } +} + +const StyledTabMenuItem = connectStyle('shoutem.ui.TabMenuItem')(TabMenuItem); + +export { StyledTabMenuItem as TabMenuItem }; diff --git a/components/TabMenu/const.js b/components/TabMenu/const.js new file mode 100644 index 00000000..b3c8be74 --- /dev/null +++ b/components/TabMenu/const.js @@ -0,0 +1,6 @@ +import PropTypes from 'prop-types'; + +export const optionShape = PropTypes.shape({ + title: PropTypes.string, + value: PropTypes.any, +}); diff --git a/components/TabMenu/index.js b/components/TabMenu/index.js new file mode 100644 index 00000000..2f185a51 --- /dev/null +++ b/components/TabMenu/index.js @@ -0,0 +1 @@ +export { TabMenu } from './TabMenu'; diff --git a/components/YearRangePicker/YearRangePicker.js b/components/YearRangePicker/YearRangePicker.js new file mode 100644 index 00000000..766c5518 --- /dev/null +++ b/components/YearRangePicker/YearRangePicker.js @@ -0,0 +1,105 @@ +import React, { PureComponent } from 'react'; +import PropTypes from 'prop-types'; +import _ from 'lodash'; +import autoBindReact from 'auto-bind/react'; +import { connectStyle } from '@shoutem/theme'; +import { View } from '../View'; +import YearPickerButton from './YearRangePickerButton'; +import YearPickerModal from './YearRangePickerModal'; + +function formatButtonTooltip(props) { + const { selectedYears, buttonPlaceholder } = props; + + if (_.isEmpty(selectedYears)) { + return buttonPlaceholder; + } + + const leadYear = _.head(selectedYears); + const lastYear = _.last(selectedYears); + + if (leadYear === lastYear) { + return leadYear.toString(); + } + + return `${leadYear}-${lastYear}`; +} + +class YearRangePicker extends PureComponent { + static propTypes = { + onRangeConfirmed: PropTypes.func, + onReset: PropTypes.func, + resetButtonTitle: PropTypes.string, + confirmButtonTitle: PropTypes.string, + selectedYears: PropTypes.arrayOf(PropTypes.number), + rangeStart: PropTypes.number, + rangeEnd: PropTypes.number, + buttonPlaceholder: PropTypes.string, + }; + + static defaultProps = { + selectedYears: [], + buttonPlaceholder: 'Year', + }; + + constructor(props) { + super(props); + + autoBindReact(this); + + this.state = { + collapsed: false, + selectedYears: props.selectedYears, + buttonTooltip: formatButtonTooltip(props), + }; + } + + componentDidUpdate(prevProps) { + const { selectedYears: prevSelectedYears } = prevProps; + const { selectedYears } = this.props; + + if (!_.isEqual(selectedYears, prevSelectedYears)) { + this.setState({ buttonTooltip: formatButtonTooltip(this.props) }); + } + } + + handleButtonPressed() { + const { collapsed } = this.state; + + this.setState({ collapsed: !collapsed }); + } + + handleRangeConfirmed(range) { + const { onRangeConfirmed } = this.props; + + this.setState({ collapsed: false }); + + if (onRangeConfirmed) { + onRangeConfirmed(range); + } + } + + render() { + const { rangeEnd, rangeStart, resetButtonTitle, confirmButtonTitle } = this.props; + const { buttonTooltip, collapsed } = this.state; + + return ( + + + + + ); + } +} + +export default connectStyle('shoutem.ui.YearRangePicker')(YearRangePicker); diff --git a/components/YearRangePicker/YearRangePickerButton.js b/components/YearRangePicker/YearRangePickerButton.js new file mode 100644 index 00000000..02a67004 --- /dev/null +++ b/components/YearRangePicker/YearRangePickerButton.js @@ -0,0 +1,82 @@ +import React, { PureComponent } from 'react'; +import { Animated } from 'react-native'; +import PropTypes from 'prop-types'; +import _ from 'lodash'; +import autoBindReact from 'auto-bind/react'; +import { connectStyle } from '@shoutem/theme'; +import { TouchableOpacity } from '../TouchableOpacity'; +import { Icon } from '../Icon'; +import { Text } from '../Text'; + +const AnimatedIcon = Animated.createAnimatedComponent(Icon); + +class YearRangePickerButton extends PureComponent { + static propTypes = { + onPress: PropTypes.func, + tooltip: PropTypes.string, + style: PropTypes.any, + }; + + constructor(props) { + super(props); + + autoBindReact(this); + + this.dropDownIconValue = new Animated.Value(0); + + this.state = { + collapsed: false, + }; + } + + handlePress() { + const { collapsed } = this.state; + const { onPress } = this.props; + + const toValue = collapsed ? 0 : 1; + + this.setState( + { collapsed: !collapsed }, + () => Animated.timing( + this.dropDownIconValue, + { + toValue, + useNativeDriver: true, + duration: 300, + } + ).start()); + + if (onPress) { + onPress(); + } + } + + render() { + const { style, tooltip } = this.props; + + return ( + + + {tooltip} + + + + ); + } +} + +export default connectStyle('shoutem.ui.YearRangePickerButton')(YearRangePickerButton); diff --git a/components/YearRangePicker/YearRangePickerModal.js b/components/YearRangePicker/YearRangePickerModal.js new file mode 100644 index 00000000..295324e2 --- /dev/null +++ b/components/YearRangePicker/YearRangePickerModal.js @@ -0,0 +1,258 @@ +import React, { PureComponent } from 'react'; +import { LayoutAnimation, Platform } from 'react-native'; +import PropTypes from 'prop-types'; +import _ from 'lodash'; +import Modal from 'react-native-modal'; +import autoBindReact from 'auto-bind/react'; +import { connectStyle } from '@shoutem/theme'; +import { View } from '../View'; +import { Text } from '../Text'; +import { Icon } from '../Icon'; +import { Button } from '../Button'; +import { TouchableOpacity } from '../TouchableOpacity'; + +const NUMBER_OF_ROWS = 4; +const YEARS_IN_ROW = 5; + +function resolveVisibleYears(props) { + const { selectedYears, rangeStart, rangeEnd } = props; + + const yearsPerPage = NUMBER_OF_ROWS * YEARS_IN_ROW; + + if (_.isEmpty(selectedYears)) { + const fullRange = _.times( + yearsPerPage, + index => rangeStart + index, + ); + + return _.filter(fullRange, year => year <= rangeEnd); + } + + const firstSelectedYear = _.head(selectedYears); + const prevPagesNumber = Math.trunc(firstSelectedYear / yearsPerPage); + + const fullRangeStart = (prevPagesNumber * yearsPerPage) + 1; + const fullRange = _.times( + yearsPerPage, + index => fullRangeStart + index, + ); + + return _.filter(fullRange, year => year <= rangeEnd); +} + +function resolveRangeTooltip(visibleYears) { + const startYear = _.head(visibleYears).toString(); + const endYear = _.last(visibleYears).toString(); + + return `${startYear}-${endYear}`; +} + +class YearRangePickerModal extends PureComponent { + static propTypes = { + onRangeConfirmed: PropTypes.func, + onDismiss: PropTypes.func, + resetButtonTitle: PropTypes.string, + confirmButtonTitle: PropTypes.string, + selectedYears: PropTypes.arrayOf(PropTypes.number), + rangeStart: PropTypes.number, + rangeEnd: PropTypes.number, + visible: PropTypes.bool, + style: PropTypes.any, + }; + + static defaultProps = { + selectedYears: [], + }; + + constructor(props) { + super(props); + + autoBindReact(this); + + this.YEARS_PER_PAGE = NUMBER_OF_ROWS * YEARS_IN_ROW; + + this.state = { + collapsed: false, + visibleYears: resolveVisibleYears(props), + selectedYears: props.selectedYears, + }; + } + + handleConfirmPress() { + const { selectedYears } = this.state; + const { onRangeConfirmed } = this.props; + + if (onRangeConfirmed) { + LayoutAnimation.easeInEaseOut(); + onRangeConfirmed(selectedYears); + } + } + + handleResetPress() { + const { onRangeConfirmed } = this.props; + + LayoutAnimation.easeInEaseOut(); + this.setState({ selectedYears: [] }); + + if (onRangeConfirmed) { + onRangeConfirmed([]); + } + } + + handleYearsForwardPress() { + const { rangeEnd } = this.props; + const { visibleYears } = this.state; + + const nextYearStart = _.last(visibleYears) + 1; + const nextYearEnd = Math.min(rangeEnd, nextYearStart + this.YEARS_PER_PAGE - 1); + + const nextVisibleYears = _.times(nextYearEnd + 1 - nextYearStart, index => nextYearStart + index); + + LayoutAnimation.easeInEaseOut(); + this.setState({ visibleYears: nextVisibleYears }); + } + + handleYearsBackPress() { + const { visibleYears } = this.state; + + const prevYearStart = _.head(visibleYears) - this.YEARS_PER_PAGE; + + LayoutAnimation.easeInEaseOut(); + this.setState({ visibleYears: _.times(this.YEARS_PER_PAGE, index => prevYearStart + index) }); + } + + handleYearPress(year) { + const { selectedYears } = this.state; + + const size = _.size(selectedYears); + const index = _.indexOf(selectedYears, year); + + LayoutAnimation.easeInEaseOut(); + + return () => { + if (_.includes(selectedYears, year)) { + if (_.last(selectedYears) === year || _.head(selectedYears) === year) { + this.setState({ selectedYears: _.without(selectedYears, year) }); + return; + } + + const cutFromEnd = size / 2 <= index; + const newYears = _.filter(selectedYears, value => cutFromEnd ? value <= year : value >= year); + + this.setState({ selectedYears: newYears }); + return; + } + + if (_.isEmpty(selectedYears)) { + this.setState({ selectedYears: [year] }); + return; + } + + const addToEnd = _.last(selectedYears) < year; + const yearsToAdd = addToEnd ? year - _.last(selectedYears) : _.head(selectedYears) - year; + + const newYears = addToEnd + ? [...selectedYears, ..._.times(yearsToAdd, index => _.last(selectedYears) + index + 1)] + : [...selectedYears, ..._.times(yearsToAdd, index => _.head(selectedYears) - index + -1)] + const sortedYears = _.sortBy(newYears, item => item); + + this.setState({ selectedYears: sortedYears }); + } + } + + renderYear(year) { + const { style } = this.props; + const { selectedYears } = this.state; + + const isSelected = _.includes(selectedYears, year); + const isFirst = _.head(selectedYears) === year; + const isLast = _.last(selectedYears) === year; + + return ( + + + {year.toString()} + + + ); + } + + renderYearRow(row, index) { + return ( + + {_.map(row, this.renderYear)} + + ) + } + + render() { + const { + style, + visible, + confirmButtonTitle, + resetButtonTitle, + rangeEnd, + rangeStart, + onDismiss, + } = this.props; + const { visibleYears } = this.state; + + const buttonTooltip = resolveRangeTooltip(visibleYears); + const data = _.chunk(visibleYears, YEARS_IN_ROW); + const nextDisabled = _.last(visibleYears) === rangeEnd; + const prevDisabled = _.head(visibleYears) - 1 < rangeStart; + + if (!visible) { + return null; + } + + return ( + + + + + {buttonTooltip} + + + {_.times(NUMBER_OF_ROWS, (row) => this.renderYearRow(data[row], row))} + + + + + + + ); + } +} + +export default connectStyle('shoutem.ui.YearRangePickerModal')(YearRangePickerModal); diff --git a/components/YearRangePicker/index.js b/components/YearRangePicker/index.js new file mode 100644 index 00000000..21382b2d --- /dev/null +++ b/components/YearRangePicker/index.js @@ -0,0 +1 @@ +export { default as YearRangePicker } from './YearRangePicker'; diff --git a/index.js b/index.js index d96653f5..d2387945 100644 --- a/index.js +++ b/index.js @@ -72,10 +72,13 @@ export { Tile } from './components/Tile'; export { Lightbox } from './components/Lightbox'; +export { InlineDropDownMenu } from './components/InlineDropDownMenu'; export { EmptyStateView } from './components/EmptyStateView'; export { EmptyListImage } from './components/EmptyListImage'; export { NumberInput } from './components/NumberInput'; export { SearchField } from './components/SearchField'; +export { TabMenu } from './components/TabMenu'; +export { YearRangePicker } from './components/YearRangePicker'; export { Examples } from './examples/components'; diff --git a/package.json b/package.json index 25c3403e..6e572947 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@shoutem/ui", - "version": "4.2.1", + "version": "4.3.0", "description": "Styleable set of components for React Native applications", "scripts": { "lint": "eslint .", @@ -25,6 +25,7 @@ "react-native-lightbox": "shoutem/react-native-lightbox#v0.7.2", "react-native-linear-gradient": "~2.5.6", "react-native-photo-view": "shoutem/react-native-photo-view#0ffa1481f6b6cb8663cb291b7db1d6644440584d", + "react-native-modal": "11.7.0", "react-native-render-html": "~4.2.0", "react-native-status-bar-height": "2.5.0", "react-native-svg": "^9.13.0", diff --git a/theme.js b/theme.js index 24f9f713..cec2dc2d 100644 --- a/theme.js +++ b/theme.js @@ -485,6 +485,10 @@ export default (variables = defaultThemeVariables) => ({ opacity: 0.5, }, + '.link': { + ...variables.links, + }, + backgroundColor: 'transparent', }, @@ -598,7 +602,7 @@ export default (variables = defaultThemeVariables) => ({ '.medium-avatar': { width: dimensionRelativeToIphone(145), height: dimensionRelativeToIphone(145), - borderRadius: 72.5, + borderRadius: dimensionRelativeToIphone(72.5), borderWidth: 0, }, @@ -661,7 +665,7 @@ export default (variables = defaultThemeVariables) => ({ }, }, 'shoutem.ui.Image': { - [INCLUDE]: ['commonVariants', 'imageSizes', 'fill-parent'], + [INCLUDE]: ['commonVariants', 'imageSizes', 'fill-parent', 'guttersMargin'], '.placeholder': { backgroundColor: inverseColorBrightnessForAmount( @@ -694,7 +698,11 @@ export default (variables = defaultThemeVariables) => ({ }, }, 'shoutem.ui.ImageBackground': { - [INCLUDE]: ['commonVariants', 'imageSizes', 'fill-parent'], + [INCLUDE]: ['commonVariants', 'imageSizes', 'fill-parent', 'guttersMargin'], + + '.overflow-hidden': { + overflow: 'hidden', + }, '.placeholder': { backgroundColor: inverseColorBrightnessForAmount( @@ -1937,6 +1945,8 @@ export default (variables = defaultThemeVariables) => ({ borderColor: variables.lineColor, }, 'shoutem.ui.Divider': { + [INCLUDE]: ['guttersMargin'], + '.line': { '.small': { width: 55, @@ -2040,6 +2050,11 @@ export default (variables = defaultThemeVariables) => ({ withoutBorder: { borderWidth: 0, }, + + '.small': { + paddingVertical: 6, + height: 42, + }, }, 'shoutem.ui.NumberInput': { @@ -2092,6 +2107,7 @@ export default (variables = defaultThemeVariables) => ({ backgroundColor: '#f0f0f0', color: '#888888', flex: 1, + minWidth: 330, fontSize: 15, height: 30, paddingVertical: 6, @@ -2551,6 +2567,17 @@ export default (variables = defaultThemeVariables) => ({ }, }, + '.relative': { + container: { + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'center', + position: 'relative', + bottom: 0, + paddingVertical: 16, + }, + }, + container: { flexDirection: 'row', alignItems: 'center', @@ -2860,4 +2887,146 @@ export default (variables = defaultThemeVariables) => ({ }, }, }, + + 'shoutem.ui.InlineDropDownMenu': { + container: { + paddingTop: 12, + paddingHorizontal: variables.mediumGutter, + paddingBottom: 4, + backgroundColor: variables.paperColor, + }, + icon: { + color: variables.text.color, + } + }, + + 'shoutem.ui.InlineDropDownMenuItem': { + container: { + paddingTop: 10, + paddingHorizontal: variables.mediumGutter, + paddingBottom: 4, + backgroundColor: variables.paperColor, + borderTopWidth: 1, + borderTopColor: variables.backgroundColor, + }, + }, + + 'shoutem.ui.TabMenu': { + container: { + paddingHorizontal: variables.smallGutter, + backgroundColor: variables.backgroundColor, + }, + list: { + flexGrow: 0, + flexShrink: 0, + }, + }, + + 'shoutem.ui.TabMenuItem': { + tabulator: { + backgroundColor: variables.text.color, + height: 1, + borderRadius: 1, + flexDirection: 'row', + marginBottom: 8, + marginLeft: 8, + }, + text: { + marginTop: 12, + marginHorizontal: 8, + marginBottom: 12, + opacity: 0.3, + }, + selectedText: { + marginBottom: 4, + opacity: 1, + } + }, + + 'shoutem.ui.YearRangePickerButton': { + container: { + flexDirection: 'row', + alignItems: 'center', + backgroundColor: '#F9F9F9', + borderWidth: 1, + borderRadius: 8, + borderColor: 'rgba(130, 130, 130, 0.1)', + paddingLeft: 15, + paddingVertical: 8, + paddingRight: 8, + marginRight: 8, + }, + icon: { + color: variables.text.color, + } + }, + + 'shoutem.ui.YearRangePickerModal': { + outerContainer: { + flex: 1, + }, + container: { + height: 360, + padding: 8, + backgroundColor: '#F9F9F9', + borderWidth: 1, + borderRadius: 8, + borderColor: 'rgba(130, 130, 130, 0.1)', + marginHorizontal: 15, + }, + tooltipContainer: { + flexDirection: 'row', + flex: 1, + justifyContent: 'space-between', + alignItems: 'center', + padding: 8, + height: 56, + }, + yearRow: { + flexDirection: 'row', + flex: 1, + }, + buttonContainer: { + flexDirection: 'row', + padding: 8, + height: 56, + }, + yearContainer: { + flex: 1, + alignSelf: 'stretch', + flexDirection: 'row', + marginBottom: 5, + justifyContent: 'center', + alignItems: 'center', + }, + year: { + position: 'absolute', + top: 0, + bottom: 0, + left: 0, + right: 0, + justifyContent: 'center', + alignItems: 'center', + }, + yearSelected: { + backgroundColor: variables.featuredColor, + }, + yearFirst: { + left: 5, + borderTopLeftRadius: 8, + borderBottomLeftRadius: 8, + }, + yearLast: { + right: 5, + borderTopRightRadius: 8, + borderBottomRightRadius: 8, + }, + icon: { + color: variables.text.color, + opacity: 1, + }, + iconDisabled: { + opacity: 0.3, + } + }, });