Skip to content

Commit

Permalink
feat: update Tab component (react-native-elements#3658)
Browse files Browse the repository at this point in the history
  • Loading branch information
arpitBhalla authored Oct 22, 2022
1 parent b7648de commit 67eb98b
Show file tree
Hide file tree
Showing 17 changed files with 140 additions and 103 deletions.
2 changes: 1 addition & 1 deletion .github/actions/install/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ runs:
- name: Setup Node.js Env
uses: actions/setup-node@v2
with:
node-version: "14"
node-version: "16"
- name: Cache dependencies
uses: actions/cache@v2
id: root_cache
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ exports[`FAB Component should match snapshot 1`] = `
style={
Object {
"alignItems": "center",
"backgroundColor": "#03dac4",
"backgroundColor": "#ad1457",
"borderColor": "#2089dc",
"borderRadius": 2,
"borderWidth": 0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ exports[`LinearProgress Component should render determinant variant 1`] = `
style={
Array [
Object {
"backgroundColor": "rgba(3, 218, 196, 0.4)",
"backgroundColor": "rgba(173, 20, 87, 0.4)",
"height": 4,
"overflow": "hidden",
"position": "relative",
Expand All @@ -34,7 +34,7 @@ exports[`LinearProgress Component should render determinant variant 1`] = `
nativeID="animatedComponent"
style={
Object {
"backgroundColor": "#03dac4",
"backgroundColor": "#ad1457",
"flex": 1,
"transform": Array [
Object {
Expand Down Expand Up @@ -70,7 +70,7 @@ exports[`LinearProgress Component should render inDeterminant variant 1`] = `
style={
Array [
Object {
"backgroundColor": "rgba(3, 218, 196, 0.4)",
"backgroundColor": "rgba(173, 20, 87, 0.4)",
"height": 4,
"overflow": "hidden",
"position": "relative",
Expand All @@ -84,7 +84,7 @@ exports[`LinearProgress Component should render inDeterminant variant 1`] = `
<View
style={
Object {
"backgroundColor": "#03dac4",
"backgroundColor": "#ad1457",
"flex": 1,
"transform": Array [
Object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ exports[`Speed Dial Component should match snapshot 1`] = `
style={
Object {
"alignItems": "center",
"backgroundColor": "#03dac4",
"backgroundColor": "#ad1457",
"borderColor": "#2089dc",
"borderRadius": 2,
"borderWidth": 0,
Expand Down Expand Up @@ -403,7 +403,7 @@ exports[`Speed Dial Component should match snapshot 1`] = `
style={
Object {
"alignItems": "center",
"backgroundColor": "#03dac4",
"backgroundColor": "#ad1457",
"borderColor": "#2089dc",
"borderRadius": 2,
"borderWidth": 0,
Expand Down Expand Up @@ -549,7 +549,7 @@ exports[`Speed Dial Component should match snapshot 1`] = `
style={
Object {
"alignItems": "center",
"backgroundColor": "#03dac4",
"backgroundColor": "#ad1457",
"borderColor": "#2089dc",
"borderRadius": 2,
"borderWidth": 0,
Expand Down
91 changes: 53 additions & 38 deletions packages/base/src/Tab/Tab.Item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,44 +4,65 @@ import { StyleProp, StyleSheet, TextStyle, ViewStyle } from 'react-native';
import { Button, ButtonProps } from '../Button';
import { defaultTheme, RneFunctionComponent } from '../helpers';

type ActiveTabItemStyle<T = {}> =
| ((active: boolean) => StyleProp<T>)
| StyleProp<T>;

export interface TabItemProps
extends Omit<
ButtonProps,
'buttonStyle' | 'titleStyle' | 'containerStyle' | 'iconContainerStyle'
> {
/** Allows to define if TabItem is active. */
active?: boolean;

/** Define the background Variant. */
variant?: 'primary' | 'default';

export interface ParentProps {
/**
* Dense Tab Item
* @default none
*/
dense?: boolean;
/**
* Additional button style
* @default none
* @type `ViewStyle or (active: boolean) => ViewStyle`
*/
buttonStyle?: ActiveTabItemStyle<ViewStyle>;

/**
* Additional button title style
* @default none
* @type TextStyle or (active: boolean) => TextStyle
*/
titleStyle?: ActiveTabItemStyle<TextStyle>;

/**
* Additional Styling for button container.
* @default none
* @type ViewStyle or (active: boolean) => ViewStyle
*/
containerStyle?: ActiveTabItemStyle<ViewStyle>;
/**
* @default none
*
*/
iconPosition?: ButtonProps['iconPosition'];
}

type ActiveTabItemStyle<T = {}> =
| ((active: boolean) => StyleProp<T>)
| StyleProp<T>;

export interface TabItemProps
extends Omit<
ButtonProps,
'buttonStyle' | 'titleStyle' | 'containerStyle' | 'iconContainerStyle'
>,
ParentProps {
/** Allows to define if TabItem is active. */
active?: boolean;

/** Define the background Variant. */
variant?: 'primary' | 'default';

/**
* Additional Styling for Icon Component container.
* @type ViewStyle or (active: boolean) => ViewStyle
*/
iconContainerStyle?: ActiveTabItemStyle<ViewStyle>;

/**
* @hidden true
*/
_parentProps?: ParentProps;
}

/**
Expand All @@ -64,21 +85,24 @@ export interface TabItemProps
export const TabItem: RneFunctionComponent<TabItemProps> = ({
active,
theme = defaultTheme,
titleStyle,
containerStyle,
buttonStyle,
_parentProps,
titleStyle = _parentProps.titleStyle,
containerStyle = _parentProps.containerStyle,
buttonStyle = _parentProps.buttonStyle,
iconPosition = _parentProps.iconPosition || 'top',
dense = _parentProps.dense,
iconContainerStyle,
variant,
iconPosition = 'top',
title,
icon,
...rest
}) => {
/**
* Allow user to define custom style for active Tab Item.
* buttonStyle={(active) => ({ backgroundColor: active ? 'red' : 'blue' })}
*/
const activeStyle = React.useCallback(
(type) => (typeof type === 'function' ? type(active) : type),
const activeProp = React.useCallback(
(prop) => (typeof prop === 'function' ? prop(active) : prop),
[active]
);

Expand All @@ -89,25 +113,26 @@ export const TabItem: RneFunctionComponent<TabItemProps> = ({
accessibilityValue={
typeof title === 'string' ? { text: title } : undefined
}
buttonStyle={[styles.buttonStyle, activeStyle(buttonStyle)]}
buttonStyle={[styles.buttonStyle, activeProp(buttonStyle)]}
titleStyle={[
styles.titleStyle,
!dense && styles.titleStyle,
{
color: variant === 'primary' ? 'white' : theme?.colors?.secondary,
paddingVertical: !rest.icon ? 8 : 2,
paddingVertical: !dense && !icon ? 8 : 2,
},
activeStyle(titleStyle),
activeProp(titleStyle),
]}
containerStyle={[
styles.containerStyle,
{
variant === 'primary' && {
backgroundColor: active
? Color(theme?.colors?.primary).darken(0.05).rgb().toString()
: 'transparent',
},
activeStyle(containerStyle),
activeProp(containerStyle),
]}
iconContainerStyle={[activeStyle(iconContainerStyle)]}
iconContainerStyle={activeProp(iconContainerStyle)}
icon={activeProp(icon)}
iconPosition={iconPosition}
title={title}
{...rest}
Expand All @@ -128,16 +153,6 @@ const styles = StyleSheet.create({
flex: 1,
borderRadius: 0,
},
viewStyle: {
flexDirection: 'row',
position: 'relative',
},
indicator: {
display: 'flex',
position: 'absolute',
height: 2,
bottom: 0,
},
});

TabItem.displayName = 'Tab.Item';
56 changes: 30 additions & 26 deletions packages/base/src/Tab/Tab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ import {
ScrollView,
LayoutChangeEvent,
} from 'react-native';
import { ParentProps } from './Tab.Item';
import { defaultTheme, RneFunctionComponent } from '../helpers';
import { TabItemProps } from './Tab.Item';

export interface TabProps extends ViewProps {
export interface TabProps extends ViewProps, ParentProps {
/** Child position index value. */
value?: number;

Expand All @@ -28,9 +29,6 @@ export interface TabProps extends ViewProps {
/** Additional styling for tab indicator. */
indicatorStyle?: StyleProp<ViewStyle>;

/** Style for Tab container */
containerStyle?: StyleProp<ViewStyle>;

/** Define the background Variant. */
variant?: 'primary' | 'default';
}
Expand All @@ -44,15 +42,22 @@ export interface TabProps extends ViewProps {
* @usage
* ### Basic Tabs
* ```tsx live
* <Tab value={0} variant='primary'>
* <Tab.Item>Tab</Tab.Item>
* <Tab.Item>Tab</Tab.Item>
* </Tab>
* function RneTab() {
* const [index, setIndex] = React.useState(0);
* return (
* <>
* <Tab value={index} onChange={setIndex} dense>
* <Tab.Item>Tab</Tab.Item>
* <Tab.Item>Tab</Tab.Item>
* </Tab>
* </>
* );
* }
* ```
*
* ### Active Tab Items
* ```tsx live
* <Tab value={0} variant="primary" scrollable>
* <Tab value={0} scrollable>
* <Tab.Item
* containerStyle={(active) => ({
* backgroundColor: active ? 'red' : undefined,
Expand All @@ -75,12 +80,17 @@ export interface TabProps extends ViewProps {
export const TabBase: RneFunctionComponent<TabProps> = ({
theme = defaultTheme,
children,
value,
value = 0,
scrollable = false,
onChange = () => {},
indicatorStyle,
disableIndicator,
variant,
variant = 'default',
style,
dense,
iconPosition,
buttonStyle,
titleStyle,
containerStyle,
...rest
}) => {
Expand Down Expand Up @@ -122,7 +132,7 @@ export const TabBase: RneFunctionComponent<TabProps> = ({
(scrollCurrentPosition + tabContainerCurrentWidth);
}

scrollViewRef.current.scrollTo({
scrollViewRef.current!.scrollTo({
x: scrollX,
y: 0,
animated: true,
Expand Down Expand Up @@ -178,7 +188,7 @@ export const TabBase: RneFunctionComponent<TabProps> = ({
backgroundColor: theme?.colors?.primary,
},
styles.viewStyle,
containerStyle,
style,
]}
onLayout={({ nativeEvent: { layout } }) => {
setTabContainerWidth(layout.width);
Expand Down Expand Up @@ -210,6 +220,13 @@ export const TabBase: RneFunctionComponent<TabProps> = ({
},
active: index === value,
variant,
_parentProps: {
dense,
iconPosition,
buttonStyle,
containerStyle,
titleStyle,
},
}
);
})}
Expand Down Expand Up @@ -238,19 +255,6 @@ export const TabBase: RneFunctionComponent<TabProps> = ({
};

const styles = StyleSheet.create({
buttonStyle: {
borderRadius: 0,
backgroundColor: 'transparent',
},
titleStyle: {
paddingHorizontal: 16,
paddingVertical: 8,
textTransform: 'uppercase',
},
containerStyle: {
flex: 1,
borderRadius: 0,
},
viewStyle: {
flexDirection: 'row',
position: 'relative',
Expand Down
5 changes: 3 additions & 2 deletions packages/base/src/Tab/__tests__/Tab.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ describe('Tab Component', () => {
))}
</Tab>
);
const TabItemComponent = queryByA11yRole('tablist');
const TabItemComponent = queryByA11yRole('tablist')!;

expect(TabItemComponent.props.style).toContainEqual({
backgroundColor: lightColors?.primary,
Expand All @@ -46,7 +46,8 @@ describe('Tab Component', () => {

const tabs = component.getAllByA11yRole('tab');
expect(tabs.length).toBe(items.length);
tabs.forEach((tab) => {
tabs.forEach((tab, index) => {
if (index === 0) return;
expect(tab.props.accessibilityState.selected).toBe(false);
expect(items.includes(tab.props.accessibilityValue.text)).toBe(true);
});
Expand Down
2 changes: 1 addition & 1 deletion packages/base/src/helpers/colors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export interface Colors {

export const lightColors: Colors = {
primary: '#2089dc',
secondary: '#03dac4',
secondary: '#ad1457',
background: '#ffffff',
white: '#ffffff',
black: '#242424',
Expand Down
Loading

0 comments on commit 67eb98b

Please sign in to comment.