@janiscommerce/ui-native 1.8.1 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,23 @@
1
+ import { FC, ReactNode } from 'react';
2
+ import { ViewStyle } from 'react-native';
3
+ interface Scene {
4
+ title: string;
5
+ scene: ReactNode;
6
+ disabled?: boolean;
7
+ }
8
+ export declare const positions: {
9
+ top: string;
10
+ bottom: string;
11
+ };
12
+ export type positionsType = typeof positions;
13
+ export type keyPosition = keyof positionsType;
14
+ interface TabsProps {
15
+ scenes: Scene[];
16
+ initialTab?: number | null;
17
+ position?: keyPosition;
18
+ onPressTabCb?: (activeTab: number) => void;
19
+ scrollContentStyle?: ViewStyle;
20
+ style?: ViewStyle;
21
+ }
22
+ declare const Tabs: FC<TabsProps>;
23
+ export default Tabs;
@@ -0,0 +1,113 @@
1
+ /* eslint-disable react-hooks/rules-of-hooks */
2
+ import React, { useEffect, useRef, useState } from 'react';
3
+ import { StyleSheet, View, ScrollView, FlatList } from 'react-native';
4
+ import { moderateScale, scaledForDevice } from '../../scale';
5
+ import { base, black, grey, primary } from '../../theme/palette';
6
+ import BaseButton from '../BaseButton';
7
+ import Text from '../Text';
8
+ import { viewportWidth } from '../../scale';
9
+ import { isObject } from '../../utils';
10
+ export const positions = {
11
+ top: 'top',
12
+ bottom: 'bottom',
13
+ };
14
+ const Tabs = ({ scenes, initialTab = null, position = positions.top, onPressTabCb = () => { }, scrollContentStyle = {}, style = {}, ...props }) => {
15
+ if (!scenes || !Array.isArray(scenes) || !scenes.length) {
16
+ return null;
17
+ }
18
+ const [activeTab, setActiveTab] = useState(0);
19
+ const scrollViewRef = useRef(null);
20
+ const validScenes = scenes.filter(({ scene, title }) => scene && title);
21
+ const areScenesValid = !!validScenes && Array.isArray(validScenes) && !!validScenes.length;
22
+ const isValidCurrentScene = !!validScenes[activeTab] &&
23
+ isObject(validScenes[activeTab]) &&
24
+ !!Object.keys(validScenes[activeTab]).length;
25
+ const contentDirection = position === positions.bottom ? 'column-reverse' : 'column';
26
+ const quantityScenes = scenes?.length;
27
+ const isScrollViewTab = quantityScenes && quantityScenes > 3;
28
+ const calculateTabs = isScrollViewTab ? { width: viewportWidth / 3 } : { flex: 1 };
29
+ const contentMargin = position === positions.bottom ? { marginBottom: 45 } : { marginTop: 45 };
30
+ const styles = StyleSheet.create({
31
+ wrapper: {
32
+ flex: 1,
33
+ position: 'relative',
34
+ flexDirection: contentDirection,
35
+ },
36
+ wrapperTab: {
37
+ position: 'absolute',
38
+ width: '100%',
39
+ height: scaledForDevice(48, moderateScale),
40
+ flexDirection: 'row',
41
+ backgroundColor: base.white,
42
+ zIndex: 1,
43
+ elevation: scaledForDevice(5, moderateScale),
44
+ },
45
+ tabButton: {
46
+ ...calculateTabs,
47
+ justifyContent: 'center',
48
+ alignItems: 'center',
49
+ borderBottomWidth: scaledForDevice(2, moderateScale),
50
+ },
51
+ title: {
52
+ textTransform: 'uppercase',
53
+ fontFamily: 'Roboto-Medium',
54
+ },
55
+ content: {
56
+ ...contentMargin,
57
+ },
58
+ });
59
+ useEffect(() => {
60
+ if (typeof initialTab === 'number') {
61
+ setActiveTab(initialTab);
62
+ }
63
+ }, [initialTab]);
64
+ useEffect(() => {
65
+ if (isScrollViewTab) {
66
+ scrollViewRef?.current?.scrollToIndex({
67
+ index: activeTab,
68
+ animated: true,
69
+ });
70
+ }
71
+ }, [activeTab, isScrollViewTab]);
72
+ const getItemLayout = (data, index) => ({
73
+ length: viewportWidth / 3,
74
+ offset: (viewportWidth / 3) * index,
75
+ index,
76
+ });
77
+ const handleScrollToIndexFailed = (info) => {
78
+ setTimeout(() => {
79
+ scrollViewRef?.current?.scrollToIndex({
80
+ index: info.index,
81
+ animated: true,
82
+ });
83
+ }, 300);
84
+ };
85
+ const TitleTab = ({ title, disabled, index }) => {
86
+ const borderBottomColor = index === activeTab ? primary.main : base.white;
87
+ const inactiveText = disabled ? grey[400] : black.main;
88
+ const textColor = index === activeTab ? primary.main : inactiveText;
89
+ const handleOnPress = (idx) => {
90
+ setActiveTab(idx);
91
+ return onPressTabCb(idx);
92
+ };
93
+ return (<BaseButton key={title + index} style={{ ...styles.tabButton, borderBottomColor }} disabled={disabled} onPress={() => handleOnPress(index)}>
94
+ <Text style={{ ...styles.title, color: textColor }} selectable={false} numberOfLines={1}>
95
+ {title}
96
+ </Text>
97
+ </BaseButton>);
98
+ };
99
+ const renderItem = ({ item, index }) => (<TitleTab title={item.title} disabled={item.disabled} index={index}/>);
100
+ return (<View style={[styles.wrapper, style]} {...props}>
101
+ {!isScrollViewTab && (<View style={styles.wrapperTab}>
102
+ {areScenesValid &&
103
+ validScenes.map((scene, idx) => (<TitleTab key={scene.title} title={scene.title} disabled={scene.disabled} index={idx}/>))}
104
+ </View>)}
105
+
106
+ {isScrollViewTab && (<FlatList style={styles.wrapperTab} data={scenes} renderItem={renderItem} ref={scrollViewRef} horizontal pagingEnabled={true} showsHorizontalScrollIndicator={false} keyExtractor={(item, index) => item.title + index} getItemLayout={getItemLayout} onScrollToIndexFailed={handleScrollToIndexFailed} initialNumToRender={quantityScenes}/>)}
107
+
108
+ {isValidCurrentScene && (<ScrollView contentContainerStyle={scrollContentStyle} style={styles.content}>
109
+ {validScenes[activeTab].scene}
110
+ </ScrollView>)}
111
+ </View>);
112
+ };
113
+ export default Tabs;
package/dist/index.d.ts CHANGED
@@ -22,5 +22,6 @@ import FullScreenMessage from './components/FullScreenMessage';
22
22
  import LayoutWithBottomButtons from './components/LayoutWithBottomButtons';
23
23
  import Toast from 'react-native-toast-message';
24
24
  import { configToast } from './components/Toast/utils';
25
+ import Tabs from './components/Tabs';
25
26
  import * as getScale from './scale';
26
- export { Text, Avatar, CheckBox, Icon, Image, Loading, Svg, StatusChip, Input, palette, LoadingFullScreen, RadioButton, Select, SwipeUp, SwipeUpFlatList, SwipeUpScrollView, SwipeUpView, Carousel, ProgressBar, List, BaseButton, Button, getScale, LayoutWithBottomButtons, FullScreenMessage, Toast, configToast, };
27
+ export { Text, Avatar, CheckBox, Icon, Image, Loading, Svg, StatusChip, Input, palette, LoadingFullScreen, RadioButton, Select, SwipeUp, SwipeUpFlatList, SwipeUpScrollView, SwipeUpView, Carousel, ProgressBar, List, BaseButton, Button, getScale, LayoutWithBottomButtons, FullScreenMessage, Toast, configToast, Tabs, };
package/dist/index.js CHANGED
@@ -22,5 +22,6 @@ import FullScreenMessage from './components/FullScreenMessage';
22
22
  import LayoutWithBottomButtons from './components/LayoutWithBottomButtons';
23
23
  import Toast from 'react-native-toast-message';
24
24
  import { configToast } from './components/Toast/utils';
25
+ import Tabs from './components/Tabs';
25
26
  import * as getScale from './scale';
26
- export { Text, Avatar, CheckBox, Icon, Image, Loading, Svg, StatusChip, Input, palette, LoadingFullScreen, RadioButton, Select, SwipeUp, SwipeUpFlatList, SwipeUpScrollView, SwipeUpView, Carousel, ProgressBar, List, BaseButton, Button, getScale, LayoutWithBottomButtons, FullScreenMessage, Toast, configToast, };
27
+ export { Text, Avatar, CheckBox, Icon, Image, Loading, Svg, StatusChip, Input, palette, LoadingFullScreen, RadioButton, Select, SwipeUp, SwipeUpFlatList, SwipeUpScrollView, SwipeUpView, Carousel, ProgressBar, List, BaseButton, Button, getScale, LayoutWithBottomButtons, FullScreenMessage, Toast, configToast, Tabs, };
@@ -0,0 +1 @@
1
+ export declare const isObject: (obj: Object) => boolean;
@@ -0,0 +1 @@
1
+ export const isObject = (obj) => !!(obj && obj.constructor === Object);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@janiscommerce/ui-native",
3
- "version": "1.8.1",
3
+ "version": "1.9.0",
4
4
  "description": "components library for Janis app",
5
5
  "main": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",