Skip to content
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

feat: added renderTile prop #47

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
35 changes: 19 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,27 +27,30 @@ Make sure you have [React Native Reanimated](https://docs.swmansion.com/react-na

## :wrench: Props

| Name | Description | Required | Type | Default |
| ----------------------- | ---------------------------------------------- | -------- | --------- | -------- |
| segments | An array of labels for segments | YES | Array | [] |
| currentIndex | Index for the currently active segment | YES | Number | 0 |
| onChange | A callback Function with pressed segment index | YES | Function | () => {} |
| badgeValues | An array of badge value for segments. | NO | Array | [] |
| isRTL | Controls the toggle animation direction | NO | Boolean | false |
| containerMargin | The value used to determine the width | NO | Number | 16 |
| activeTextStyle | active text styles | NO | TextStyle | {} |
| inactiveTextStyle | inactive text styles. | NO | TextStyle | {} |
| segmentedControlWrapper | Style object for the Segmented Control. | NO | ViewStyle | {} |
| pressableWrapper | Style object for the Pressable Container | NO | ViewStyle | {} |
| tileStyle | Style object for the Absolute positioned tile | NO | ViewStyle | {} |
| activeBadgeStyle | Active Badge Style | NO | ViewStyle | {} |
| inactiveBadgeStyle | Inactive Badge Style | NO | ViewStyle | {} |
| badgeTextStyle | Badge text styles | NO | TextStyle | {} |
| Name | Description | Required | Type | Default |
| ----------------------- | ---------------------------------------------- | -------- | --------- | -------- |
| segments | An array of labels for segments | YES | Array | [] |
| currentIndex | Index for the currently active segment | YES | Number | 0 |
| onChange | A callback Function with pressed segment index | YES | Function | () => {} |
| badgeValues | An array of badge value for segments. | NO | Array | [] |
| isRTL | Controls the toggle animation direction | NO | Boolean | false |
| containerMargin | The value used to determine the width | NO | Number | 16 |
| activeTextStyle | active text styles | NO | TextStyle | {} |
| inactiveTextStyle | inactive text styles. | NO | TextStyle | {} |
| segmentedControlWrapper | Style object for the Segmented Control. | NO | ViewStyle | {} |
| pressableWrapper | Style object for the Pressable Container | NO | ViewStyle | {} |
| tileStyle | Style object for the Absolute positioned tile | NO | ViewStyle | {} |
| activeBadgeStyle | Active Badge Style | NO | ViewStyle | {} |
| inactiveBadgeStyle | Inactive Badge Style | NO | ViewStyle | {} |
| badgeTextStyle | Badge text styles | NO | TextStyle | {} |
| renderTile | Render a custom tile component | NO | Function | undefined |

> :warning: all View styles or Text Styles passed as props overrides some default styles provided by the package. Make sure you use it properly :)

> :information_source: To apply your own `shadowStyles` use the tileStyle prop

> :information_source: `renderTile` takes a function with `style`, `transform` and `width`. You can use these to style your custom tile to look the same as the default style (e.g. if you just wanted to change the animation)

## :mag: Usage

```tsx
Expand Down
56 changes: 44 additions & 12 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@ import Animated, {
} from 'react-native-reanimated';
import { widthPercentageToDP } from 'react-native-responsive-screen';

export interface TileProps {
/** Styles of the default tile */
style: ViewStyle;
/** The React Native Reanimated transform style with translateX */
transform: ViewStyle['transform'];
/** The full width of tile */
width: number;
}

interface SegmentedControlProps {
/**
* The Segments Text Array
Expand Down Expand Up @@ -72,6 +81,10 @@ interface SegmentedControlProps {
* Badge Text Styles
*/
badgeTextStyle?: TextStyle;
/**
* Render a custom tile component
*/
renderTile?: (props: TileProps) => React.ReactNode;
}

const defaultShadowStyle = {
Expand Down Expand Up @@ -110,6 +123,7 @@ const SegmentedControl: React.FC<SegmentedControlProps> = ({
activeBadgeStyle,
inactiveBadgeStyle,
badgeTextStyle,
renderTile,
}: SegmentedControlProps) => {
const width = widthPercentageToDP('100%') - containerMargin * 2;
const translateValue = width / segments.length;
Expand Down Expand Up @@ -177,22 +191,40 @@ const SegmentedControl: React.FC<SegmentedControlProps> = ({
...badgeTextStyle,
};

const flattenedTileStyle: ViewStyle = StyleSheet.flatten<ViewStyle>([
styles.movingSegmentStyle,
defaultShadowStyle,
StyleSheet.absoluteFill,
{
width: width / segments.length - 4,
},
tileStyle,
]);

const memoizedTile = React.useMemo<React.ReactNode>(() => {
if (renderTile) {
return renderTile({
style: flattenedTileStyle,
transform: tabTranslateAnimatedStyles.transform,
width: translateValue,
});
}

return (
<Animated.View style={[flattenedTileStyle, tabTranslateAnimatedStyles]} />
);
}, [
flattenedTileStyle,
renderTile,
tabTranslateAnimatedStyles,
translateValue,
]);

return (
<Animated.View
style={[styles.defaultSegmentedControlWrapper, segmentedControlWrapper]}
>
<Animated.View
style={[
styles.movingSegmentStyle,
defaultShadowStyle,
tileStyle,
StyleSheet.absoluteFill,
{
width: width / segments.length - 4,
},
tabTranslateAnimatedStyles,
]}
/>
{memoizedTile}
{segments.map((segment, index) => {
return (
<Pressable
Expand Down