= (props) => (
13 |
14 |
15 |
16 | );
17 |
18 | it('should render component passed to children', () => {
19 | render(
20 |
21 | I love Ficus UI (forked from Magnus UI)
22 |
23 | );
24 |
25 | expect(
26 | screen.getByText('I love Ficus UI (forked from Magnus UI)')
27 | ).toBeTruthy();
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/src/components/center/center.type.tsx:
--------------------------------------------------------------------------------
1 | import type { ViewProps as RNViewProps } from 'react-native';
2 |
3 | import type {
4 | BorderPropsType,
5 | SpacingPropsType,
6 | BorderRadiusPropsType,
7 | ShadowPropsType,
8 | DimensionPropsType,
9 | BackgroundPropsType,
10 | BackgroundImgPropsType,
11 | FlexPropsType,
12 | PositionPropsType,
13 | ZIndexPropsType,
14 | OverflowPropsType,
15 | OpacityPropsType,
16 | VariantPropsType,
17 | } from '../../types';
18 |
19 | export interface CenterProps
20 | extends RNViewProps,
21 | BorderPropsType,
22 | SpacingPropsType,
23 | BorderRadiusPropsType,
24 | ShadowPropsType,
25 | DimensionPropsType,
26 | BackgroundPropsType,
27 | BackgroundImgPropsType,
28 | FlexPropsType,
29 | PositionPropsType,
30 | ZIndexPropsType,
31 | OverflowPropsType,
32 | OpacityPropsType,
33 | VariantPropsType {}
34 |
--------------------------------------------------------------------------------
/src/components/checkbox/checkbox.type.tsx:
--------------------------------------------------------------------------------
1 | import { PressableProps as RNButtonProps } from 'react-native';
2 | import {
3 | BackgroundPropsType,
4 | ButtonPropsType,
5 | DimensionPropsType,
6 | DisabledPropsType,
7 | FlexPropsType,
8 | OpacityPropsType,
9 | PositionPropsType,
10 | PrefixSuffixPropsType,
11 | TextPropsType,
12 | ZIndexPropsType,
13 | BorderPropsType,
14 | SpacingPropsType,
15 | BorderRadiusPropsType,
16 | ShadowPropsType,
17 | VariantPropsType,
18 | } from '../../types';
19 | import { BoxProps } from '../box/box.type';
20 | import { CheckboxGroup } from './group.component';
21 |
22 | export type CompundedCheckbox = React.FunctionComponent
& {
23 | Group: typeof CheckboxGroup;
24 | };
25 |
26 | export interface CheckboxProps
27 | extends Omit,
28 | BorderPropsType,
29 | SpacingPropsType,
30 | ShadowPropsType,
31 | BorderRadiusPropsType,
32 | DimensionPropsType,
33 | PositionPropsType,
34 | FlexPropsType,
35 | PrefixSuffixPropsType,
36 | OpacityPropsType,
37 | ZIndexPropsType,
38 | DisabledPropsType,
39 | Pick,
40 | Pick,
41 | Omit,
42 | VariantPropsType {
43 | colorScheme?: string;
44 | defaultChecked?: boolean;
45 | icon?: string | React.ReactNode;
46 | iconColor?: string;
47 | isChecked?: boolean;
48 | isLoading?: boolean;
49 | onChecked?: (newValue: boolean) => void;
50 | onChange?: (value: any) => void;
51 | value?: any;
52 | children?:
53 | | ((states: CheckboxStates) => React.ReactNode)
54 | | React.ReactNode
55 | | string;
56 | size?: number | 'sm' | 'lg';
57 | }
58 |
59 | export interface CheckboxGroupProps extends BoxProps {
60 | onChange?: (value: any[]) => void;
61 | value?: any[];
62 | defaultValue?: any[];
63 | children: React.ReactElement[] | React.ReactElement;
64 | colorScheme?: string;
65 | }
66 |
67 | export interface CheckboxStates {
68 | isChecked?: boolean;
69 | isDisabled?: boolean;
70 | isLoading?: boolean;
71 | }
72 |
--------------------------------------------------------------------------------
/src/components/checkbox/group.component.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { useState } from 'react';
3 | import { useDefaultProps } from '../../utilities/useDefaultProps';
4 |
5 | import { Box } from '../box/box.component';
6 | import { CheckboxGroupProps } from './checkbox.type';
7 |
8 | const CheckboxGroup: React.FunctionComponent = (
9 | incomingProps
10 | ) => {
11 | const props = useDefaultProps('CheckboxGroup', incomingProps, {});
12 |
13 | const [value, setValue] = useState(props.value ?? props.defaultValue ?? []);
14 | const {
15 | children,
16 | onChange: onChangeProp,
17 | value: propsValue,
18 | colorScheme,
19 | ...rest
20 | } = props;
21 |
22 | /**
23 | * checks if checked value is already in the state or not,
24 | * if it, remove it else add it
25 | *
26 | * @param value
27 | */
28 | const onChange = (optionValue: any) => {
29 | const optionIndex = value.indexOf(optionValue);
30 | const newValue = [...value];
31 |
32 | if (optionIndex === -1) {
33 | newValue.push(optionValue);
34 | } else {
35 | newValue.splice(optionIndex, 1);
36 | }
37 |
38 | if (!('value' in props)) {
39 | setValue(newValue);
40 | }
41 |
42 | if (onChangeProp) {
43 | onChangeProp(newValue);
44 | }
45 | };
46 |
47 | /**
48 | * clones the children and add checked, onChange prop
49 | */
50 | const renderChildren = () => {
51 | return React.Children.map(children, (child: React.ReactElement) => {
52 | return React.cloneElement(child, {
53 | onChange,
54 | isChecked: value.indexOf(child.props.value) > -1,
55 | ...(colorScheme ? { colorScheme } : {}),
56 | });
57 | });
58 | };
59 |
60 | return {renderChildren()};
61 | };
62 |
63 | export { CheckboxGroup };
64 |
--------------------------------------------------------------------------------
/src/components/divider/divider.spec.tsx:
--------------------------------------------------------------------------------
1 | import { render, screen } from '@testing-library/react-native';
2 | import { Divider } from './divider.component';
3 | import React from 'react';
4 |
5 | describe('Divider component', () => {
6 | it('should render correctly', () => {
7 | const dividerId = 'dividerId';
8 |
9 | render();
10 |
11 | const divider = screen.getByTestId(dividerId);
12 | expect(divider).toBeDefined();
13 | });
14 |
15 | it('should apply orientation prop correctly', () => {
16 | const horizontalDividerId = 'horizonaltDivider';
17 | const verticalDividerId = 'verticalDivider';
18 |
19 | render(
20 | <>
21 |
22 |
23 | >
24 | );
25 |
26 | const horizontalDivider = screen.getByTestId(horizontalDividerId);
27 | const verticalDivider = screen.getByTestId(verticalDividerId);
28 |
29 | expect(horizontalDivider).toHaveStyle({
30 | borderLeftWidth: 0,
31 | borderTopWidth: 1,
32 | });
33 | expect(verticalDivider).toHaveStyle({
34 | borderLeftWidth: 1,
35 | borderTopWidth: 0,
36 | });
37 | });
38 |
39 | it('should apply size prop correctly', () => {
40 | const horizontalDividerId = 'horizonaltDivider';
41 | const verticalDividerId = 'verticalDivider';
42 |
43 | render(
44 | <>
45 |
46 |
47 | >
48 | );
49 |
50 | const horizontalDivider = screen.getByTestId(horizontalDividerId);
51 | const verticalDivider = screen.getByTestId(verticalDividerId);
52 |
53 | expect(horizontalDivider).toHaveStyle({ borderTopWidth: 5 });
54 | expect(verticalDivider).toHaveStyle({ borderLeftWidth: 5 });
55 | });
56 | });
57 |
--------------------------------------------------------------------------------
/src/components/divider/divider.type.tsx:
--------------------------------------------------------------------------------
1 | import type { ViewProps as RNViewProps } from 'react-native';
2 |
3 | import type {
4 | BorderPropsType,
5 | SpacingPropsType,
6 | BorderRadiusPropsType,
7 | ShadowPropsType,
8 | DimensionPropsType,
9 | FlexPropsType,
10 | PositionPropsType,
11 | ZIndexPropsType,
12 | OverflowPropsType,
13 | OpacityPropsType,
14 | VariantPropsType,
15 | OrientationPropsType,
16 | } from '../../types';
17 |
18 | export interface DividerProps
19 | extends RNViewProps,
20 | OrientationPropsType,
21 | BorderPropsType,
22 | SpacingPropsType,
23 | BorderRadiusPropsType,
24 | ShadowPropsType,
25 | DimensionPropsType,
26 | FlexPropsType,
27 | PositionPropsType,
28 | ZIndexPropsType,
29 | OverflowPropsType,
30 | OpacityPropsType,
31 | VariantPropsType {
32 | colorScheme?: string;
33 | size?: number;
34 | }
35 |
--------------------------------------------------------------------------------
/src/components/draggable-modal/draggable-modal.style.tsx:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import { ThemeType } from '../../theme';
3 | import {
4 | createSpacingStyles,
5 | createBorderWidthStyles,
6 | createBorderColorStyles,
7 | createBorderRadiusStyles,
8 | getThemeColor,
9 | } from '../../theme/theme.service';
10 | import { DraggableModalProps } from './draggable-modal.type';
11 |
12 | /**
13 | * computed style
14 | *
15 | * @param theme
16 | * @param props
17 | */
18 | export const getStyle = (theme: ThemeType, props: DraggableModalProps) => {
19 | const computedStyle: any = {};
20 |
21 | computedStyle.modal = {
22 | margin: 0,
23 | justifyContent: props.justifyContent,
24 | };
25 |
26 | computedStyle.container = {
27 | ...createBorderWidthStyles(props),
28 | ...createSpacingStyles(props, theme.spacing),
29 | ...createBorderColorStyles(props, theme.colors),
30 | ...createBorderRadiusStyles(props, theme.borderRadius),
31 | backgroundColor: getThemeColor(theme.colors, props.bg as string),
32 | };
33 |
34 | computedStyle.safeView = {
35 | flex: 1,
36 | };
37 |
38 | // merging style props to computed style
39 | if (props.style) {
40 | computedStyle.modal = {
41 | ...computedStyle.modal,
42 | // @ts-ignore
43 | ...props.style,
44 | };
45 | }
46 |
47 | return StyleSheet.create(computedStyle);
48 | };
49 |
--------------------------------------------------------------------------------
/src/components/draggable-modal/draggable-modal.type.tsx:
--------------------------------------------------------------------------------
1 | import { BottomSheetModalProps } from '@gorhom/bottom-sheet';
2 | import {
3 | BorderPropsType,
4 | SpacingPropsType,
5 | BorderRadiusPropsType,
6 | BackgroundPropsType,
7 | DimensionPropsType,
8 | FlexPropsType,
9 | VariantPropsType,
10 | } from '../../types';
11 |
12 | export interface DraggableModalProps
13 | extends BottomSheetModalProps,
14 | BorderPropsType,
15 | SpacingPropsType,
16 | BorderRadiusPropsType,
17 | Pick,
18 | Pick,
19 | Pick,
20 | VariantPropsType {
21 | children: React.ReactElement[] | React.ReactElement;
22 | isOpen?: boolean;
23 | onClose?: () => void;
24 | }
25 |
--------------------------------------------------------------------------------
/src/components/flashlist/flashlist.spec.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render } from '@testing-library/react-native';
3 |
4 | import { Text } from '../text/text.component';
5 | import { FlashList } from './flashlist.component';
6 | import type { FlashListProps } from './flashlist.type';
7 | import { ThemeProvider } from '../../theme/theme.provider';
8 |
9 | jest.mock('react-native-toast-message', () => 'Toast');
10 |
11 | describe('FlashList component', () => {
12 | const TestList: React.FC = (props) => (
13 |
14 |
15 |
16 | );
17 |
18 | it('should render component passed to children', () => {
19 | render(
20 | {item.text}}
23 | keyExtractor={(item) => item.id}
24 | estimatedItemSize={200}
25 | />
26 | );
27 | });
28 | });
29 |
--------------------------------------------------------------------------------
/src/components/flashlist/flashlist.style.tsx:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 |
3 | import {
4 | createShadowStyles,
5 | createPositionStyle,
6 | createSpacingStyles,
7 | createBorderWidthStyles,
8 | createBorderColorStyles,
9 | createBorderRadiusStyles,
10 | getThemeColor,
11 | } from '../../theme/theme.service';
12 | import type { FlashListProps } from './flashlist.type';
13 | import type { ThemeType } from '../../theme/type';
14 |
15 | /**
16 | * computed style
17 | *
18 | * @param theme
19 | * @param props
20 | */
21 | export const getStyle = (theme: ThemeType, props: FlashListProps) => {
22 | const computedStyle: any = {};
23 |
24 | computedStyle.list = {
25 | flexDirection: props.direction ? props.direction : props.flexDirection,
26 | flexWrap: props.wrap ? props.wrap : props.flexWrap,
27 | alignItems: props.align ? props.align : props.alignItems,
28 | justifyContent: props.justify ? props.justify : props.justifyContent,
29 | flexBasis: props.basis ? props.basis : props.flexBasis,
30 | flexGrow: props.grow ? props.grow : props.flexGrow,
31 | flexShrink: props.shrink ? props.shrink : props.flexShrink,
32 | height: props.h,
33 | width: props.w,
34 | minWidth: props.minW,
35 | minHeight: props.minH,
36 | alignSelf: props.alignSelf,
37 | maxWidth: props.maxW,
38 | maxHeight: props.maxH,
39 | opacity: props.opacity,
40 | overflow: props.overflow || 'hidden',
41 | zIndex: props.zIndex,
42 | borderStyle: props.borderStyle,
43 | backgroundColor: getThemeColor(theme.colors, props.bg as string),
44 | flex: props.flex,
45 | ...createPositionStyle(props),
46 | ...createShadowStyles(props, theme),
47 | ...createBorderWidthStyles(props),
48 | ...createSpacingStyles(props, theme.spacing),
49 | ...createBorderColorStyles(props, theme.colors),
50 | ...createBorderRadiusStyles(props, theme.borderRadius),
51 | };
52 |
53 | // merging custom style props to computed style
54 | if (props.style) {
55 | computedStyle.list = {
56 | ...computedStyle.list,
57 | // @ts-ignore
58 | ...props.style,
59 | };
60 | }
61 |
62 | return StyleSheet.create(computedStyle);
63 | };
64 |
--------------------------------------------------------------------------------
/src/components/flashlist/flashlist.type.tsx:
--------------------------------------------------------------------------------
1 | import { FlashListProps as ShopifyFlashListProps } from '@shopify/flash-list';
2 |
3 | import type {
4 | BorderPropsType,
5 | SpacingPropsType,
6 | BorderRadiusPropsType,
7 | ShadowPropsType,
8 | DimensionPropsType,
9 | BackgroundPropsType,
10 | FlexPropsType,
11 | PositionPropsType,
12 | ZIndexPropsType,
13 | OverflowPropsType,
14 | OpacityPropsType,
15 | VariantPropsType,
16 | } from '../../types';
17 |
18 | export interface FlashListProps
19 | extends ShopifyFlashListProps,
20 | BorderPropsType,
21 | SpacingPropsType,
22 | BorderRadiusPropsType,
23 | ShadowPropsType,
24 | DimensionPropsType,
25 | BackgroundPropsType,
26 | FlexPropsType,
27 | PositionPropsType,
28 | ZIndexPropsType,
29 | OverflowPropsType,
30 | OpacityPropsType,
31 | VariantPropsType {}
32 |
--------------------------------------------------------------------------------
/src/components/flex/flex.spec.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render, screen } from '@testing-library/react-native';
3 |
4 | import { Text } from '../text/text.component';
5 | import { Flex } from './flex.component';
6 | import type { FlexProps } from './flex.type';
7 | import { ThemeProvider } from '../../theme/theme.provider';
8 |
9 | jest.mock('react-native-toast-message', () => 'Toast');
10 |
11 | describe('Flex component', () => {
12 | const TestFlex: React.FC = (props) => (
13 |
14 |
15 |
16 | );
17 |
18 | it('should render component passed to children', () => {
19 | render(
20 |
21 | I love Ficus UI (forked from Magnus UI)
22 |
23 | );
24 |
25 | expect(
26 | screen.getByText('I love Ficus UI (forked from Magnus UI)')
27 | ).toBeTruthy();
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/src/components/flex/flex.type.tsx:
--------------------------------------------------------------------------------
1 | import type { ViewProps as RNViewProps } from 'react-native';
2 |
3 | import type {
4 | BorderPropsType,
5 | SpacingPropsType,
6 | BorderRadiusPropsType,
7 | ShadowPropsType,
8 | DimensionPropsType,
9 | BackgroundPropsType,
10 | BackgroundImgPropsType,
11 | FlexPropsType,
12 | PositionPropsType,
13 | ZIndexPropsType,
14 | OverflowPropsType,
15 | OpacityPropsType,
16 | VariantPropsType,
17 | } from '../../types';
18 |
19 | export interface FlexProps
20 | extends RNViewProps,
21 | BorderPropsType,
22 | SpacingPropsType,
23 | BorderRadiusPropsType,
24 | ShadowPropsType,
25 | DimensionPropsType,
26 | BackgroundPropsType,
27 | BackgroundImgPropsType,
28 | FlexPropsType,
29 | PositionPropsType,
30 | ZIndexPropsType,
31 | OverflowPropsType,
32 | OpacityPropsType,
33 | VariantPropsType {}
34 |
--------------------------------------------------------------------------------
/src/components/icon-button/icon-button.component.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { IconButtonProps } from './icon-button.type';
3 | import { Button } from '../button/button.component';
4 | import { getThemeProperty, useTheme } from '../../theme';
5 |
6 | const IconButton: React.FunctionComponent = ({
7 | icon,
8 | size = 'md',
9 | ...incomingProps
10 | }) => {
11 | const { theme } = useTheme();
12 | return (
13 |
29 | );
30 | };
31 |
32 | export { IconButton };
33 |
--------------------------------------------------------------------------------
/src/components/icon-button/icon-button.type.ts:
--------------------------------------------------------------------------------
1 | import { ButtonProps } from '../button/button.type';
2 |
3 | export interface IconButtonProps extends Omit {
4 | icon: React.ReactNode;
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/icon/icon.service.tsx:
--------------------------------------------------------------------------------
1 | import IconEntypo from 'react-native-vector-icons/Entypo';
2 | import IconZocial from 'react-native-vector-icons/Zocial';
3 | import IconFeather from 'react-native-vector-icons/Feather';
4 | import IconIonicons from 'react-native-vector-icons/Ionicons';
5 | import IconOcticons from 'react-native-vector-icons/Octicons';
6 | import IconAntDesign from 'react-native-vector-icons/AntDesign';
7 | import IconEvilIcons from 'react-native-vector-icons/EvilIcons';
8 | import IconFoundation from 'react-native-vector-icons/Foundation';
9 | import IconFontAwesome from 'react-native-vector-icons/FontAwesome';
10 | import IconFontAwesome5 from 'react-native-vector-icons/FontAwesome5';
11 | import IconMaterialIcons from 'react-native-vector-icons/MaterialIcons';
12 | import IconSimpleLineIcons from 'react-native-vector-icons/SimpleLineIcons';
13 | import IconMaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
14 |
15 | import { iconFontFamilyType } from './icon.type';
16 |
17 | /**
18 | * get icon set
19 | */
20 | export const getIconSet = (fontFamily: iconFontFamilyType = 'FontAwesome') => {
21 | switch (fontFamily) {
22 | case 'AntDesign':
23 | return IconAntDesign;
24 | case 'Entypo':
25 | return IconEntypo;
26 | case 'EvilIcons':
27 | return IconEvilIcons;
28 | case 'Feather':
29 | return IconFeather;
30 | case 'FontAwesome':
31 | return IconFontAwesome;
32 | case 'FontAwesome5':
33 | return IconFontAwesome5;
34 | case 'Foundation':
35 | return IconFoundation;
36 | case 'Ionicons':
37 | return IconIonicons;
38 | case 'MaterialIcons':
39 | return IconMaterialIcons;
40 | case 'MaterialCommunityIcons':
41 | return IconMaterialCommunityIcons;
42 | case 'Zocial':
43 | return IconZocial;
44 | case 'SimpleLineIcons':
45 | return IconSimpleLineIcons;
46 | case 'Octicons':
47 | return IconOcticons;
48 | case 'Ionicons':
49 | return IconIonicons;
50 | default:
51 | return IconAntDesign;
52 | }
53 | };
54 |
--------------------------------------------------------------------------------
/src/components/icon/icon.style.tsx:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import { ThemeType } from '../../theme';
3 |
4 | import {
5 | getThemeProperty,
6 | createShadowStyles,
7 | createSpacingStyles,
8 | createBorderColorStyles,
9 | createBorderWidthStyles,
10 | createBorderRadiusStyles,
11 | getThemeColor,
12 | } from '../../theme/theme.service';
13 | import { IconProps } from './icon.type';
14 |
15 | /**
16 | * computed style
17 | *
18 | * @param theme
19 | * @param props
20 | */
21 | export const getStyle = (theme: ThemeType, props: IconProps) => {
22 | const computedStyle: any = {};
23 |
24 | computedStyle.container = {
25 | height: props.h,
26 | width: props.w,
27 | minHeight: props.minH,
28 | minWidth: props.minW,
29 | maxWidth: props.maxW,
30 | maxHeight: props.maxH,
31 | top: props.top,
32 | left: props.left,
33 | right: props.right,
34 | bottom: props.bottom,
35 | position: props.position,
36 | alignSelf: props.alignSelf,
37 | alignItems: 'center',
38 | justifyContent: 'center',
39 | opacity: props.opacity,
40 | color: getThemeColor(theme.colors, props.color as string),
41 | fontSize: getThemeProperty(theme.fontSize, props.fontSize),
42 | backgroundColor: getThemeColor(theme.colors, props.bg as string),
43 | ...createBorderWidthStyles(props),
44 | ...createSpacingStyles(props, theme.spacing),
45 | ...createBorderColorStyles(props, theme.colors),
46 | ...createBorderRadiusStyles(props, theme.borderRadius),
47 | ...createShadowStyles(props, theme),
48 | };
49 |
50 | // merging style props to computed style
51 | if (props.style) {
52 | computedStyle.container = {
53 | ...computedStyle.container,
54 | // @ts-ignore
55 | ...props.style,
56 | };
57 | }
58 |
59 | return StyleSheet.create(computedStyle);
60 | };
61 |
--------------------------------------------------------------------------------
/src/components/icon/icon.type.tsx:
--------------------------------------------------------------------------------
1 | import { ViewProps as RNViewProps } from 'react-native';
2 | import {
3 | BackgroundPropsType,
4 | DimensionPropsType,
5 | FlexPropsType,
6 | OpacityPropsType,
7 | PositionPropsType,
8 | TextPropsType,
9 | ZIndexPropsType,
10 | BorderPropsType,
11 | SpacingPropsType,
12 | BorderRadiusPropsType,
13 | ShadowPropsType,
14 | VariantPropsType,
15 | } from '../../types';
16 |
17 | export type iconFontFamilyType =
18 | | 'AntDesign'
19 | | 'Entypo'
20 | | 'EvilIcons'
21 | | 'Feather'
22 | | 'FontAwesome'
23 | | 'FontAwesome5'
24 | | 'Foundation'
25 | | 'Ionicons'
26 | | 'MaterialIcons'
27 | | 'MaterialCommunityIcons'
28 | | 'Octicons'
29 | | 'Zocial'
30 | | 'Fontisto'
31 | | 'SimpleLineIcons';
32 |
33 | export interface IconProps
34 | extends RNViewProps,
35 | BorderPropsType,
36 | SpacingPropsType,
37 | BorderRadiusPropsType,
38 | ShadowPropsType,
39 | DimensionPropsType,
40 | PositionPropsType,
41 | ZIndexPropsType,
42 | OpacityPropsType,
43 | Pick,
44 | Pick,
45 | Pick,
46 | VariantPropsType {
47 | name: string;
48 | fontFamily?: iconFontFamilyType;
49 | }
50 |
--------------------------------------------------------------------------------
/src/components/image/image.component.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { Image as RNImage } from 'react-native';
3 |
4 | import { getStyle } from './image.style';
5 | import type { ImageProps } from './image.type';
6 | import { useTheme } from '../../theme/theme.hook';
7 | import { useDefaultProps } from '../../utilities/useDefaultProps';
8 | import { handleResponsiveProps } from '../../types';
9 |
10 | const Image: React.FunctionComponent = (incomingProps) => {
11 | const { theme, windowWidth } = useTheme();
12 | const props = useDefaultProps(
13 | 'Image',
14 | handleResponsiveProps(incomingProps, theme, windowWidth),
15 | {}
16 | );
17 |
18 | const {
19 | bg,
20 | h,
21 | w,
22 | m,
23 | mt,
24 | mr,
25 | mb,
26 | ml,
27 | ms,
28 | p,
29 | pr,
30 | pt,
31 | pb,
32 | pl,
33 | minH,
34 | minW,
35 | maxW,
36 | maxH,
37 | position,
38 | style,
39 | flexDirection,
40 | direction,
41 | borderRadius,
42 | borderTopRadius,
43 | borderTopLeftRadius,
44 | borderTopRightRadius,
45 | borderBottomLeftRadius,
46 | borderBottomRightRadius,
47 | borderLeftRadius,
48 | borderRightRadius,
49 | borderBottomRadius,
50 | alignItems,
51 | align,
52 | justifyContent,
53 | justify,
54 | borderColor,
55 | borderBottomColor,
56 | borderLeftColor,
57 | borderTopColor,
58 | borderRightColor,
59 | borderWidth,
60 | borderLeftWidth,
61 | borderRightWidth,
62 | borderBottomWidth,
63 | borderTopWidth,
64 | borderEndWidth,
65 | flexWrap,
66 | wrap,
67 | flexGrow,
68 | grow,
69 | flexBasis,
70 | basis,
71 | flexShrink,
72 | shrink,
73 | shadow,
74 | shadowColor,
75 | boxShadow,
76 | filter,
77 | opacity,
78 | overflow,
79 | top,
80 | left,
81 | right,
82 | bottom,
83 | zIndex,
84 | ...rest
85 | } = props;
86 | const computedStyle = getStyle(theme, props);
87 |
88 | return ;
89 | };
90 |
91 | // Image.defaultProps = {};
92 |
93 | export { Image };
94 |
--------------------------------------------------------------------------------
/src/components/image/image.spec.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render } from '@testing-library/react-native';
3 |
4 | import { Image } from './image.component';
5 | import type { ImageProps } from './image.type';
6 | import { ThemeProvider } from '../../theme/theme.provider';
7 |
8 | jest.mock('react-native-toast-message', () => 'Toast');
9 |
10 | describe('Image component', () => {
11 | const TestImage: React.FC = (props) => (
12 |
13 |
14 |
15 | );
16 |
17 | it('should render component passed to children', () => {
18 | render(
19 |
22 | );
23 | });
24 | });
25 |
--------------------------------------------------------------------------------
/src/components/image/image.style.tsx:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 |
3 | import {
4 | createShadowStyles,
5 | createPositionStyle,
6 | createSpacingStyles,
7 | createBorderWidthStyles,
8 | createBorderColorStyles,
9 | createBorderRadiusStyles,
10 | getThemeColor,
11 | } from '../../theme/theme.service';
12 | import type { ImageProps } from './image.type';
13 | import type { ThemeType } from '../../theme/type';
14 |
15 | /**
16 | * computed style
17 | *
18 | * @param theme
19 | * @param props
20 | */
21 | export const getStyle = (theme: ThemeType, props: ImageProps) => {
22 | const computedStyle: any = {};
23 |
24 | computedStyle.image = {
25 | flexDirection: props.direction ? props.direction : props.flexDirection,
26 | flexWrap: props.wrap ? props.wrap : props.flexWrap,
27 | alignItems: props.align ? props.align : props.alignItems,
28 | justifyContent: props.justify ? props.justify : props.justifyContent,
29 | flexBasis: props.basis ? props.basis : props.flexBasis,
30 | flexGrow: props.grow ? props.grow : props.flexGrow,
31 | flexShrink: props.shrink ? props.shrink : props.flexShrink,
32 | height: props.h,
33 | width: props.w,
34 | minWidth: props.minW,
35 | minHeight: props.minH,
36 | alignSelf: props.alignSelf,
37 | maxWidth: props.maxW,
38 | maxHeight: props.maxH,
39 | opacity: props.opacity,
40 | overflow: props.overflow || 'hidden',
41 | zIndex: props.zIndex,
42 | borderStyle: props.borderStyle,
43 | backgroundColor: getThemeColor(theme.colors, props.bg as string),
44 | flex: props.flex,
45 | ...createPositionStyle(props),
46 | ...createShadowStyles(props, theme),
47 | ...createBorderWidthStyles(props),
48 | ...createSpacingStyles(props, theme.spacing),
49 | ...createBorderColorStyles(props, theme.colors),
50 | ...createBorderRadiusStyles(props, theme.borderRadius),
51 | };
52 |
53 | // merging custom style props to computed style
54 | if (props.style) {
55 | computedStyle.image = {
56 | ...computedStyle.image,
57 | // @ts-ignore
58 | ...props.style,
59 | };
60 | }
61 |
62 | return StyleSheet.create(computedStyle);
63 | };
64 |
--------------------------------------------------------------------------------
/src/components/image/image.type.tsx:
--------------------------------------------------------------------------------
1 | import type { ImageProps as RNImageProps } from 'react-native';
2 |
3 | import type {
4 | BorderPropsType,
5 | SpacingPropsType,
6 | BorderRadiusPropsType,
7 | ShadowPropsType,
8 | DimensionPropsType,
9 | BackgroundPropsType,
10 | FlexPropsType,
11 | PositionPropsType,
12 | ZIndexPropsType,
13 | OverflowPropsType,
14 | OpacityPropsType,
15 | VariantPropsType,
16 | } from '../../types';
17 |
18 | export interface ImageProps
19 | extends Omit<
20 | RNImageProps,
21 | | 'borderBottomLeftRadius'
22 | | 'borderBottomRightRadius'
23 | | 'borderRadius'
24 | | 'borderTopLeftRadius'
25 | | 'borderTopRightRadius'
26 | >,
27 | BorderPropsType,
28 | SpacingPropsType,
29 | BorderRadiusPropsType,
30 | ShadowPropsType,
31 | DimensionPropsType,
32 | BackgroundPropsType,
33 | FlexPropsType,
34 | PositionPropsType,
35 | ZIndexPropsType,
36 | OverflowPropsType,
37 | OpacityPropsType,
38 | VariantPropsType {}
39 |
--------------------------------------------------------------------------------
/src/components/input/input.type.tsx:
--------------------------------------------------------------------------------
1 | import { TextInputProps as RNTextInputProps } from 'react-native';
2 | import {
3 | BackgroundPropsType,
4 | DimensionPropsType,
5 | FlexPropsType,
6 | InputPropsType,
7 | LoadingPropsType,
8 | OpacityPropsType,
9 | PrefixSuffixPropsType,
10 | TextPropsType,
11 | ZIndexPropsType,
12 | BorderPropsType,
13 | SpacingPropsType,
14 | BorderRadiusPropsType,
15 | ShadowPropsType,
16 | VariantPropsType,
17 | } from '../../types';
18 |
19 | export interface InputProps
20 | extends RNTextInputProps,
21 | BorderPropsType,
22 | SpacingPropsType,
23 | ShadowPropsType,
24 | BorderRadiusPropsType,
25 | DimensionPropsType,
26 | LoadingPropsType,
27 | PrefixSuffixPropsType,
28 | ZIndexPropsType,
29 | OpacityPropsType,
30 | Pick,
31 | Pick,
32 | Omit,
33 | InputPropsType,
34 | VariantPropsType {}
35 |
--------------------------------------------------------------------------------
/src/components/input/textarea.type.tsx:
--------------------------------------------------------------------------------
1 | import { InputProps } from './input.type';
2 |
3 | export interface TextareaProps extends InputProps {}
4 |
--------------------------------------------------------------------------------
/src/components/list/list.component.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { FlatList, View } from 'react-native';
3 |
4 | import { getStyle } from './list.style';
5 | import type { ListProps } from './list.type';
6 | import { useTheme } from '../../theme/theme.hook';
7 | import { useDefaultProps } from '../../utilities/useDefaultProps';
8 | import { handleResponsiveProps } from '../../types';
9 |
10 | const List: React.FunctionComponent = (incomingProps) => {
11 | const { theme, windowWidth } = useTheme();
12 | const props = useDefaultProps(
13 | 'List',
14 | handleResponsiveProps(incomingProps, theme, windowWidth),
15 | { flex: 1 }
16 | );
17 |
18 | const {
19 | bg,
20 | h,
21 | w,
22 | m,
23 | mt,
24 | mr,
25 | mb,
26 | ml,
27 | ms,
28 | p,
29 | pr,
30 | pt,
31 | pb,
32 | pl,
33 | minH,
34 | minW,
35 | maxW,
36 | maxH,
37 | position,
38 | style,
39 | flexDirection,
40 | direction,
41 | borderRadius,
42 | borderTopRadius,
43 | borderTopLeftRadius,
44 | borderTopRightRadius,
45 | borderBottomLeftRadius,
46 | borderBottomRightRadius,
47 | borderLeftRadius,
48 | borderRightRadius,
49 | borderBottomRadius,
50 | children,
51 | alignItems,
52 | align,
53 | justifyContent,
54 | justify,
55 | borderColor,
56 | borderBottomColor,
57 | borderLeftColor,
58 | borderTopColor,
59 | borderRightColor,
60 | borderWidth,
61 | borderLeftWidth,
62 | borderRightWidth,
63 | borderBottomWidth,
64 | borderTopWidth,
65 | borderEndWidth,
66 | flexWrap,
67 | wrap,
68 | flexGrow,
69 | grow,
70 | flexBasis,
71 | basis,
72 | flexShrink,
73 | shrink,
74 | shadow,
75 | shadowColor,
76 | boxShadow,
77 | filter,
78 | opacity,
79 | overflow,
80 | top,
81 | left,
82 | right,
83 | bottom,
84 | zIndex,
85 | ...rest
86 | } = props;
87 | const computedStyle = getStyle(theme, props);
88 |
89 | return (
90 |
91 |
92 |
93 | );
94 | };
95 |
96 | // List.defaultProps = {};
97 |
98 | export { List };
99 |
--------------------------------------------------------------------------------
/src/components/list/list.spec.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render } from '@testing-library/react-native';
3 |
4 | import { Text } from '../text/text.component';
5 | import { List } from './list.component';
6 | import type { ListProps } from './list.type';
7 | import { ThemeProvider } from '../../theme/theme.provider';
8 |
9 | jest.mock('react-native-toast-message', () => 'Toast');
10 |
11 | describe('List component', () => {
12 | const TestList: React.FC = (props) => (
13 |
14 |
15 |
16 | );
17 |
18 | it('should render component passed to children', () => {
19 | render(
20 | {item.text}}
23 | keyExtractor={(item) => item.id}
24 | />
25 | );
26 | });
27 | });
28 |
--------------------------------------------------------------------------------
/src/components/list/list.style.tsx:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 |
3 | import {
4 | createShadowStyles,
5 | createPositionStyle,
6 | createSpacingStyles,
7 | createBorderWidthStyles,
8 | createBorderColorStyles,
9 | createBorderRadiusStyles,
10 | getThemeColor,
11 | } from '../../theme/theme.service';
12 | import type { ListProps } from './list.type';
13 | import type { ThemeType } from '../../theme/type';
14 |
15 | /**
16 | * computed style
17 | *
18 | * @param theme
19 | * @param props
20 | */
21 | export const getStyle = (theme: ThemeType, props: ListProps) => {
22 | const computedStyle: any = {};
23 |
24 | computedStyle.list = {
25 | flexDirection: props.direction ? props.direction : props.flexDirection,
26 | flexWrap: props.wrap ? props.wrap : props.flexWrap,
27 | alignItems: props.align ? props.align : props.alignItems,
28 | justifyContent: props.justify ? props.justify : props.justifyContent,
29 | flexBasis: props.basis ? props.basis : props.flexBasis,
30 | flexGrow: props.grow ? props.grow : props.flexGrow,
31 | flexShrink: props.shrink ? props.shrink : props.flexShrink,
32 | height: props.h,
33 | width: props.w,
34 | minWidth: props.minW,
35 | minHeight: props.minH,
36 | alignSelf: props.alignSelf,
37 | maxWidth: props.maxW,
38 | maxHeight: props.maxH,
39 | opacity: props.opacity,
40 | overflow: props.overflow || 'hidden',
41 | zIndex: props.zIndex,
42 | borderStyle: props.borderStyle,
43 | backgroundColor: getThemeColor(theme.colors, props.bg as string),
44 | flex: props.flex,
45 | ...createPositionStyle(props),
46 | ...createShadowStyles(props, theme),
47 | ...createBorderWidthStyles(props),
48 | ...createSpacingStyles(props, theme.spacing),
49 | ...createBorderColorStyles(props, theme.colors),
50 | ...createBorderRadiusStyles(props, theme.borderRadius),
51 | };
52 |
53 | // merging custom style props to computed style
54 | if (props.style) {
55 | computedStyle.list = {
56 | ...computedStyle.list,
57 | // @ts-ignore
58 | ...props.style,
59 | };
60 | }
61 |
62 | return StyleSheet.create(computedStyle);
63 | };
64 |
--------------------------------------------------------------------------------
/src/components/list/list.type.tsx:
--------------------------------------------------------------------------------
1 | import { FlatListProps } from 'react-native';
2 |
3 | import type {
4 | BorderPropsType,
5 | SpacingPropsType,
6 | BorderRadiusPropsType,
7 | ShadowPropsType,
8 | DimensionPropsType,
9 | BackgroundPropsType,
10 | FlexPropsType,
11 | PositionPropsType,
12 | ZIndexPropsType,
13 | OverflowPropsType,
14 | OpacityPropsType,
15 | VariantPropsType,
16 | } from '../../types';
17 |
18 | export interface ListProps
19 | extends FlatListProps,
20 | BorderPropsType,
21 | SpacingPropsType,
22 | BorderRadiusPropsType,
23 | ShadowPropsType,
24 | DimensionPropsType,
25 | BackgroundPropsType,
26 | FlexPropsType,
27 | PositionPropsType,
28 | ZIndexPropsType,
29 | OverflowPropsType,
30 | OpacityPropsType,
31 | VariantPropsType {}
32 |
--------------------------------------------------------------------------------
/src/components/modal/modal.style.tsx:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import { ThemeType } from '../../theme';
3 | import {
4 | createSpacingStyles,
5 | createBorderWidthStyles,
6 | createBorderColorStyles,
7 | createBorderRadiusStyles,
8 | } from '../../theme/theme.service';
9 | import { ModalProps } from './modal.type';
10 |
11 | /**
12 | * computed style
13 | *
14 | * @param theme
15 | * @param props
16 | */
17 | export const getStyle = (theme: ThemeType, props: ModalProps) => {
18 | const computedStyle: any = {};
19 |
20 | computedStyle.modal = {
21 | margin: 0,
22 | justifyContent: props.justifyContent,
23 | };
24 |
25 | computedStyle.container = {
26 | ...createBorderWidthStyles(props),
27 | ...createSpacingStyles(props, theme.spacing),
28 | ...createBorderColorStyles(props, theme.colors),
29 | ...createBorderRadiusStyles(props, theme.borderRadius),
30 | };
31 |
32 | computedStyle.safeView = {
33 | flex: 1,
34 | };
35 |
36 | // merging style props to computed style
37 | if (props.style) {
38 | computedStyle.modal = {
39 | ...computedStyle.modal,
40 | // @ts-ignore
41 | ...props.style,
42 | };
43 | }
44 |
45 | return StyleSheet.create(computedStyle);
46 | };
47 |
--------------------------------------------------------------------------------
/src/components/modal/modal.type.tsx:
--------------------------------------------------------------------------------
1 | import { ModalProps as RNModalProps } from 'react-native-modal';
2 | import {
3 | BorderPropsType,
4 | SpacingPropsType,
5 | BorderRadiusPropsType,
6 | BackgroundPropsType,
7 | DimensionPropsType,
8 | FlexPropsType,
9 | VariantPropsType,
10 | } from '../../types';
11 |
12 | export interface ModalProps
13 | extends Partial,
14 | BorderPropsType,
15 | SpacingPropsType,
16 | BorderRadiusPropsType,
17 | Pick,
18 | Pick,
19 | Pick,
20 | VariantPropsType {
21 | children: React.ReactElement[] | React.ReactElement;
22 | isOpen?: boolean;
23 | }
24 |
--------------------------------------------------------------------------------
/src/components/pin-input/pin-input.style.tsx:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 |
3 | import {
4 | createShadowStyles,
5 | createPositionStyle,
6 | createSpacingStyles,
7 | createBorderRadiusStyles,
8 | getThemeColor,
9 | } from '../../theme/theme.service';
10 | import type { PinInputProps } from './pin-input.type';
11 | import type { ThemeType } from '../../theme/type';
12 |
13 | /**
14 | * computed style
15 | *
16 | * @param theme
17 | * @param props
18 | */
19 | export const getStyle = (theme: ThemeType, props: PinInputProps) => {
20 | const computedStyle: any = {};
21 |
22 | computedStyle.pininput = {
23 | flexDirection: props.direction ? props.direction : props.flexDirection,
24 | flexWrap: props.wrap ? props.wrap : props.flexWrap,
25 | alignItems: props.align ? props.align : props.alignItems,
26 | justifyContent: props.justify ? props.justify : props.justifyContent,
27 | flexBasis: props.basis ? props.basis : props.flexBasis,
28 | flexGrow: props.grow ? props.grow : props.flexGrow,
29 | flexShrink: props.shrink ? props.shrink : props.flexShrink,
30 | height: props.h,
31 | width: props.w,
32 | minWidth: props.minW,
33 | minHeight: props.minH,
34 | alignSelf: props.alignSelf,
35 | maxWidth: props.maxW,
36 | maxHeight: props.maxH,
37 | opacity: props.opacity,
38 | overflow: props.overflow || 'hidden',
39 | zIndex: props.zIndex,
40 | borderStyle: props.borderStyle,
41 | backgroundColor: getThemeColor(theme.colors, props.bg as string),
42 | flex: props.flex,
43 | ...createPositionStyle(props),
44 | ...createShadowStyles(props, theme),
45 | ...createSpacingStyles(props, theme.spacing),
46 | };
47 |
48 | // merging custom style props to computed style
49 | if (props.style) {
50 | computedStyle.pininput = {
51 | ...computedStyle.pininput,
52 | // @ts-ignore
53 | ...props.style,
54 | };
55 | }
56 |
57 | computedStyle.pininputItem = {
58 | ...createBorderRadiusStyles(props, theme.borderRadius),
59 | };
60 |
61 | return StyleSheet.create(computedStyle);
62 | };
63 |
--------------------------------------------------------------------------------
/src/components/pin-input/pin-input.type.tsx:
--------------------------------------------------------------------------------
1 | import type { ViewProps as RNViewProps } from 'react-native';
2 |
3 | import type {
4 | BorderPropsType,
5 | SpacingPropsType,
6 | BorderRadiusPropsType,
7 | ShadowPropsType,
8 | DimensionPropsType,
9 | BackgroundPropsType,
10 | FlexPropsType,
11 | PositionPropsType,
12 | ZIndexPropsType,
13 | OverflowPropsType,
14 | OpacityPropsType,
15 | VariantPropsType,
16 | InputPropsType,
17 | } from '../../types';
18 | import { CodeFieldProps } from 'react-native-confirmation-code-field';
19 |
20 | export interface PinInputProps
21 | extends CodeFieldProps,
22 | RNViewProps,
23 | BorderPropsType,
24 | SpacingPropsType,
25 | BorderRadiusPropsType,
26 | ShadowPropsType,
27 | DimensionPropsType,
28 | BackgroundPropsType,
29 | FlexPropsType,
30 | PositionPropsType,
31 | ZIndexPropsType,
32 | OverflowPropsType,
33 | OpacityPropsType,
34 | VariantPropsType,
35 | InputPropsType {
36 | colorScheme?: string;
37 | mask?: boolean;
38 | placeholder?: string;
39 | }
40 |
--------------------------------------------------------------------------------
/src/components/pressable/pressable.spec.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render, screen } from '@testing-library/react-native';
3 |
4 | import { Text } from '../text/text.component';
5 | import { Pressable } from './pressable.component';
6 | import type { PressableProps } from './pressable.type';
7 | import { ThemeProvider } from '../../theme/theme.provider';
8 |
9 | jest.mock('react-native-toast-message', () => 'Toast');
10 |
11 | describe('Pressable component', () => {
12 | const TestPressable: React.FC = (props) => (
13 |
14 |
15 |
16 | );
17 |
18 | it('should render component passed to children', () => {
19 | render(
20 |
21 | I love Ficus UI (forked from Magnus UI)
22 |
23 | );
24 |
25 | expect(
26 | screen.getByText('I love Ficus UI (forked from Magnus UI)')
27 | ).toBeTruthy();
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/src/components/pressable/pressable.style.tsx:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 |
3 | import {
4 | createShadowStyles,
5 | createPositionStyle,
6 | createSpacingStyles,
7 | createBorderWidthStyles,
8 | createBorderColorStyles,
9 | createBorderRadiusStyles,
10 | getThemeColor,
11 | } from '../../theme/theme.service';
12 | import type { PressableProps } from './pressable.type';
13 | import type { ThemeType } from '../../theme/type';
14 |
15 | /**
16 | * computed style
17 | *
18 | * @param theme
19 | * @param props
20 | */
21 | export const getStyle = (theme: ThemeType, props: PressableProps) => {
22 | const computedStyle: any = {};
23 |
24 | computedStyle.pressable = {
25 | flexDirection: props.direction ? props.direction : props.flexDirection,
26 | flexWrap: props.wrap ? props.wrap : props.flexWrap,
27 | alignItems: props.align ? props.align : props.alignItems,
28 | justifyContent: props.justify ? props.justify : props.justifyContent,
29 | flexBasis: props.basis ? props.basis : props.flexBasis,
30 | flexGrow: props.grow ? props.grow : props.flexGrow,
31 | flexShrink: props.shrink ? props.shrink : props.flexShrink,
32 | height: props.h,
33 | width: props.w,
34 | minWidth: props.minW,
35 | minHeight: props.minH,
36 | alignSelf: props.alignSelf,
37 | maxWidth: props.maxW,
38 | maxHeight: props.maxH,
39 | opacity: props.opacity,
40 | overflow: props.overflow || 'hidden',
41 | zIndex: props.zIndex,
42 | borderStyle: props.borderStyle,
43 | backgroundColor: getThemeColor(theme.colors, props.bg as string),
44 | flex: props.flex,
45 | ...createPositionStyle(props),
46 | ...createShadowStyles(props, theme),
47 | ...createBorderWidthStyles(props),
48 | ...createSpacingStyles(props, theme.spacing),
49 | ...createBorderColorStyles(props, theme.colors),
50 | ...createBorderRadiusStyles(props, theme.borderRadius),
51 | };
52 |
53 | // merging custom style props to computed style
54 | if (props.style) {
55 | computedStyle.pressable = {
56 | ...computedStyle.pressable,
57 | // @ts-ignore
58 | ...props.style,
59 | };
60 | }
61 |
62 | return StyleSheet.create(computedStyle);
63 | };
64 |
--------------------------------------------------------------------------------
/src/components/pressable/pressable.type.tsx:
--------------------------------------------------------------------------------
1 | import type { PressableProps as RNPressableProps } from 'react-native';
2 |
3 | import type {
4 | BorderPropsType,
5 | SpacingPropsType,
6 | BorderRadiusPropsType,
7 | ShadowPropsType,
8 | DimensionPropsType,
9 | BackgroundPropsType,
10 | FlexPropsType,
11 | PositionPropsType,
12 | ZIndexPropsType,
13 | OverflowPropsType,
14 | OpacityPropsType,
15 | VariantPropsType,
16 | } from '../../types';
17 |
18 | export interface PressableProps
19 | extends RNPressableProps,
20 | BorderPropsType,
21 | SpacingPropsType,
22 | BorderRadiusPropsType,
23 | ShadowPropsType,
24 | DimensionPropsType,
25 | BackgroundPropsType,
26 | FlexPropsType,
27 | PositionPropsType,
28 | ZIndexPropsType,
29 | OverflowPropsType,
30 | OpacityPropsType,
31 | VariantPropsType {}
32 |
--------------------------------------------------------------------------------
/src/components/radio/group.component.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { useState } from 'react';
3 |
4 | import { RadioGroupProps } from './radio.type';
5 | import { Box } from '../box/box.component';
6 | import { useDefaultProps } from '../../utilities/useDefaultProps';
7 | import { handleResponsiveProps } from '../../types';
8 | import { useTheme } from '../../theme';
9 |
10 | const RadioGroup: React.FunctionComponent = (
11 | incomingProps
12 | ) => {
13 | const { theme, windowWidth } = useTheme();
14 | const props = useDefaultProps(
15 | 'RadioGroup',
16 | handleResponsiveProps(incomingProps, theme, windowWidth),
17 | {}
18 | );
19 |
20 | const [value, setValue] = useState(props.value ?? props.defaultValue ?? null);
21 | const {
22 | children,
23 | onChange: onChangeProp,
24 | value: propsValue,
25 | colorScheme,
26 | ...rest
27 | } = props;
28 |
29 | /**
30 | * checks if checked value is already in the state or not,
31 | * if it, remove it else add it
32 | *
33 | * @param value
34 | */
35 | const onChange = (optionValue: any) => {
36 | if (!('value' in props)) {
37 | setValue(optionValue);
38 | }
39 |
40 | if (onChangeProp) {
41 | onChangeProp(optionValue);
42 | }
43 | };
44 |
45 | /**
46 | * clones the children and add isChecked, onChange prop
47 | */
48 | const renderChildren = () => {
49 | return React.Children.map(children, (child: React.ReactElement) => {
50 | return React.cloneElement(child, {
51 | onChange,
52 | isChecked: value === child.props.value,
53 | ...(colorScheme ? { colorScheme } : {}),
54 | });
55 | });
56 | };
57 |
58 | return {renderChildren()};
59 | };
60 |
61 | export { RadioGroup };
62 |
--------------------------------------------------------------------------------
/src/components/radio/radio.service.tsx:
--------------------------------------------------------------------------------
1 | import { ThemeType } from '../../theme';
2 | import { getThemeColor } from '../../theme/theme.service';
3 |
4 | /**
5 | * get icon name to be used based on checked state
6 | *
7 | * @param checked
8 | */
9 | export const getIconName = (checked: boolean = false) => {
10 | switch (true) {
11 | case checked:
12 | return 'radio-button-checked';
13 | default:
14 | return 'radio-button-unchecked';
15 | }
16 | };
17 |
18 | /**
19 | * get icon color based on state
20 | *
21 | * @param checked
22 | * @param disabled
23 | */
24 | export const getIconColor = (
25 | isChecked: any,
26 | isDisabled: any,
27 | iconColor: any,
28 | theme: ThemeType
29 | ) => {
30 | switch (true) {
31 | case isDisabled:
32 | return getThemeColor(theme.colors, 'transparent');
33 | case isChecked:
34 | return getThemeColor(theme.colors, iconColor);
35 | default:
36 | return getThemeColor(theme.colors, 'transparent');
37 | }
38 | };
39 |
--------------------------------------------------------------------------------
/src/components/radio/radio.type.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { PressableProps as RNButtonProps } from 'react-native';
3 | import {
4 | BackgroundPropsType,
5 | ButtonPropsType,
6 | DimensionPropsType,
7 | DisabledPropsType,
8 | FlexPropsType,
9 | OpacityPropsType,
10 | PositionPropsType,
11 | PrefixSuffixPropsType,
12 | TextPropsType,
13 | ZIndexPropsType,
14 | BorderPropsType,
15 | SpacingPropsType,
16 | BorderRadiusPropsType,
17 | ShadowPropsType,
18 | VariantPropsType,
19 | } from '../../types';
20 | import { BoxProps } from '../box/box.type';
21 | import { RadioGroup } from './group.component';
22 |
23 | export type CompoundedRadio = React.FunctionComponent
& {
24 | Group: typeof RadioGroup;
25 | };
26 |
27 | export interface RadioProps
28 | extends Omit,
29 | BorderPropsType,
30 | SpacingPropsType,
31 | ShadowPropsType,
32 | BorderRadiusPropsType,
33 | PositionPropsType,
34 | DimensionPropsType,
35 | FlexPropsType,
36 | DisabledPropsType,
37 | PrefixSuffixPropsType,
38 | OpacityPropsType,
39 | ZIndexPropsType,
40 | Omit,
41 | Pick,
42 | Pick,
43 | VariantPropsType {
44 | colorScheme?: string;
45 | defaultChecked?: boolean;
46 | icon?: string | React.ReactNode;
47 | iconColor?: string;
48 | isChecked?: boolean;
49 | isLoading?: boolean;
50 | onChange?: (value: any) => void;
51 | value?: any;
52 | children: ((states: RadioStates) => React.ReactNode) | React.ReactNode;
53 | size?: number | 'sm' | 'lg';
54 | }
55 |
56 | export interface RadioStates {
57 | isFocused?: boolean;
58 | isChecked?: boolean;
59 | isDisabled?: boolean;
60 | isLoading?: boolean;
61 | }
62 |
63 | export interface RadioGroupProps extends BoxProps {
64 | onChange?: (value: any) => void;
65 | value?: any;
66 | defaultValue?: any;
67 | children: React.ReactElement[] | React.ReactElement;
68 | colorScheme?: string;
69 | }
70 |
71 | // Backwards compatibility
72 | export type IRadioProps = RadioProps;
73 |
--------------------------------------------------------------------------------
/src/components/safeareabox/safeareabox.spec.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render, screen } from '@testing-library/react-native';
3 |
4 | import { Text } from '../text/text.component';
5 | import { SafeAreaBox } from './safeareabox.component';
6 | import type { SafeAreaBoxProps } from './safeareabox.type';
7 | import { ThemeProvider } from '../../theme/theme.provider';
8 |
9 | jest.mock('react-native-toast-message', () => 'Toast');
10 |
11 | describe('SafeAreaBox component', () => {
12 | const TestSafeAreaBox: React.FC = (props) => (
13 |
14 |
15 |
16 | );
17 |
18 | it('should render component passed to children', () => {
19 | render(
20 |
21 | I love Ficus UI (forked from Magnus UI)
22 |
23 | );
24 |
25 | expect(
26 | screen.getByText('I love Ficus UI (forked from Magnus UI)')
27 | ).toBeTruthy();
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/src/components/safeareabox/safeareabox.type.tsx:
--------------------------------------------------------------------------------
1 | import type { ViewProps as RNViewProps } from 'react-native';
2 |
3 | import type {
4 | BorderPropsType,
5 | SpacingPropsType,
6 | BorderRadiusPropsType,
7 | ShadowPropsType,
8 | DimensionPropsType,
9 | BackgroundPropsType,
10 | FlexPropsType,
11 | PositionPropsType,
12 | ZIndexPropsType,
13 | OverflowPropsType,
14 | OpacityPropsType,
15 | VariantPropsType,
16 | } from '../../types';
17 |
18 | export interface SafeAreaBoxProps
19 | extends RNViewProps,
20 | BorderPropsType,
21 | SpacingPropsType,
22 | BorderRadiusPropsType,
23 | ShadowPropsType,
24 | DimensionPropsType,
25 | BackgroundPropsType,
26 | FlexPropsType,
27 | PositionPropsType,
28 | ZIndexPropsType,
29 | OverflowPropsType,
30 | OpacityPropsType,
31 | VariantPropsType {}
32 |
--------------------------------------------------------------------------------
/src/components/scrollbox/scrollbox.spec.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render, screen } from '@testing-library/react-native';
3 |
4 | import { Text } from '../text/text.component';
5 | import { ScrollBox } from './scrollbox.component';
6 | import type { ScrollBoxProps } from './scrollbox.type';
7 | import { ThemeProvider } from '../../theme/theme.provider';
8 |
9 | jest.mock('react-native-toast-message', () => 'Toast');
10 |
11 | describe('ScrollBox component', () => {
12 | const TestScrollBox: React.FC = (props) => (
13 |
14 |
15 |
16 | );
17 |
18 | it('should render component passed to children', () => {
19 | render(
20 |
21 | I love Ficus UI (forked from Magnus UI)
22 |
23 | );
24 |
25 | expect(
26 | screen.getByText('I love Ficus UI (forked from Magnus UI)')
27 | ).toBeTruthy();
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/src/components/scrollbox/scrollbox.style.tsx:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 |
3 | import {
4 | createShadowStyles,
5 | createPositionStyle,
6 | createSpacingStyles,
7 | createBorderWidthStyles,
8 | createBorderColorStyles,
9 | createBorderRadiusStyles,
10 | getThemeColor,
11 | } from '../../theme/theme.service';
12 | import type { ScrollBoxProps } from './scrollbox.type';
13 | import type { ThemeType } from '../../theme/type';
14 |
15 | /**
16 | * computed style
17 | *
18 | * @param theme
19 | * @param props
20 | */
21 | export const getStyle = (theme: ThemeType, props: ScrollBoxProps) => {
22 | const computedStyle: any = {};
23 |
24 | computedStyle.scrollbox = {
25 | flexDirection: props.direction ? props.direction : props.flexDirection,
26 | flexWrap: props.wrap ? props.wrap : props.flexWrap,
27 | alignItems: props.align ? props.align : props.alignItems,
28 | justifyContent: props.justify ? props.justify : props.justifyContent,
29 | flexBasis: props.basis ? props.basis : props.flexBasis,
30 | flexGrow: props.grow ? props.grow : props.flexGrow,
31 | flexShrink: props.shrink ? props.shrink : props.flexShrink,
32 | height: props.h,
33 | width: props.w,
34 | minWidth: props.minW,
35 | minHeight: props.minH,
36 | alignSelf: props.alignSelf,
37 | maxWidth: props.maxW,
38 | maxHeight: props.maxH,
39 | opacity: props.opacity,
40 | overflow: props.overflow || 'hidden',
41 | zIndex: props.zIndex,
42 | borderStyle: props.borderStyle,
43 | backgroundColor: getThemeColor(theme.colors, props.bg as string),
44 | flex: props.flex,
45 | ...createPositionStyle(props),
46 | ...createShadowStyles(props, theme),
47 | ...createBorderWidthStyles(props),
48 | ...createSpacingStyles(props, theme.spacing),
49 | ...createBorderColorStyles(props, theme.colors),
50 | ...createBorderRadiusStyles(props, theme.borderRadius),
51 | };
52 |
53 | // merging custom style props to computed style
54 | if (props.style) {
55 | computedStyle.scrollbox = {
56 | ...computedStyle.scrollbox,
57 | // @ts-ignore
58 | ...props.style,
59 | };
60 | }
61 |
62 | return StyleSheet.create(computedStyle);
63 | };
64 |
--------------------------------------------------------------------------------
/src/components/scrollbox/scrollbox.type.tsx:
--------------------------------------------------------------------------------
1 | import type { ScrollViewProps as RNScrollViewProps } from 'react-native';
2 |
3 | import type {
4 | BorderPropsType,
5 | SpacingPropsType,
6 | BorderRadiusPropsType,
7 | ShadowPropsType,
8 | DimensionPropsType,
9 | BackgroundPropsType,
10 | FlexPropsType,
11 | PositionPropsType,
12 | ZIndexPropsType,
13 | OverflowPropsType,
14 | OpacityPropsType,
15 | VariantPropsType,
16 | } from '../../types';
17 |
18 | export interface ScrollBoxProps
19 | extends RNScrollViewProps,
20 | BorderPropsType,
21 | SpacingPropsType,
22 | BorderRadiusPropsType,
23 | ShadowPropsType,
24 | DimensionPropsType,
25 | BackgroundPropsType,
26 | FlexPropsType,
27 | PositionPropsType,
28 | ZIndexPropsType,
29 | OverflowPropsType,
30 | OpacityPropsType,
31 | VariantPropsType {}
32 |
--------------------------------------------------------------------------------
/src/components/sectionlist/sectionlist.component.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { SectionList as RNSectionList } from 'react-native';
3 |
4 | import { getStyle } from './sectionlist.style';
5 | import type { SectionListProps } from './sectionlist.type';
6 | import { useTheme } from '../../theme/theme.hook';
7 | import { useDefaultProps } from '../../utilities/useDefaultProps';
8 | import { handleResponsiveProps } from '../../types';
9 |
10 | const SectionList: React.FunctionComponent = (
11 | incomingProps
12 | ) => {
13 | const { theme, windowWidth } = useTheme();
14 | const props = useDefaultProps(
15 | 'SectionList',
16 | handleResponsiveProps(incomingProps, theme, windowWidth),
17 | {}
18 | );
19 |
20 | const {
21 | bg,
22 | h,
23 | w,
24 | m,
25 | mt,
26 | mr,
27 | mb,
28 | ml,
29 | ms,
30 | p,
31 | pr,
32 | pt,
33 | pb,
34 | pl,
35 | minH,
36 | minW,
37 | maxW,
38 | maxH,
39 | position,
40 | style,
41 | flexDirection,
42 | direction,
43 | borderRadius,
44 | borderTopRadius,
45 | borderTopLeftRadius,
46 | borderTopRightRadius,
47 | borderBottomLeftRadius,
48 | borderBottomRightRadius,
49 | borderLeftRadius,
50 | borderRightRadius,
51 | borderBottomRadius,
52 | children,
53 | alignItems,
54 | align,
55 | justifyContent,
56 | justify,
57 | borderColor,
58 | borderBottomColor,
59 | borderLeftColor,
60 | borderTopColor,
61 | borderRightColor,
62 | borderWidth,
63 | borderLeftWidth,
64 | borderRightWidth,
65 | borderBottomWidth,
66 | borderTopWidth,
67 | borderEndWidth,
68 | flexWrap,
69 | wrap,
70 | flexGrow,
71 | grow,
72 | flexBasis,
73 | basis,
74 | flexShrink,
75 | shrink,
76 | shadow,
77 | shadowColor,
78 | boxShadow,
79 | filter,
80 | opacity,
81 | overflow,
82 | top,
83 | left,
84 | right,
85 | bottom,
86 | zIndex,
87 | ...rest
88 | } = props;
89 | const computedStyle = getStyle(theme, props);
90 |
91 | return ;
92 | };
93 |
94 | // SectionList.defaultProps = {};
95 |
96 | export { SectionList };
97 |
--------------------------------------------------------------------------------
/src/components/sectionlist/sectionlist.spec.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render, screen } from '@testing-library/react-native';
3 |
4 | import { Text } from '../text/text.component';
5 | import { Box } from '../box/box.component';
6 | import { SectionList } from './sectionlist.component';
7 | import type { SectionListProps } from './sectionlist.type';
8 | import { ThemeProvider } from '../../theme/theme.provider';
9 |
10 | jest.mock('react-native-toast-message', () => 'Toast');
11 |
12 | describe('SectionList component', () => {
13 | const TestSectionList: React.FC = (props) => (
14 |
15 |
16 |
17 | );
18 |
19 | it('should render component passed to children', () => {
20 | render(
21 | (
26 |
27 | {item}
28 |
29 | )}
30 | renderSectionHeader={({ section: { title } }) => {title}}
31 | keyExtractor={(item) => item}
32 | />
33 | );
34 |
35 | expect(
36 | screen.getByText('I love Ficus UI (forked from Magnus UI)')
37 | ).toBeTruthy();
38 | });
39 | });
40 |
--------------------------------------------------------------------------------
/src/components/sectionlist/sectionlist.style.tsx:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 |
3 | import {
4 | createShadowStyles,
5 | createPositionStyle,
6 | createSpacingStyles,
7 | createBorderWidthStyles,
8 | createBorderColorStyles,
9 | createBorderRadiusStyles,
10 | getThemeColor,
11 | } from '../../theme/theme.service';
12 | import type { SectionListProps } from './sectionlist.type';
13 | import type { ThemeType } from '../../theme/type';
14 |
15 | /**
16 | * computed style
17 | *
18 | * @param theme
19 | * @param props
20 | */
21 | export const getStyle = (theme: ThemeType, props: SectionListProps) => {
22 | const computedStyle: any = {};
23 |
24 | computedStyle.sectionlist = {
25 | flexDirection: props.direction ? props.direction : props.flexDirection,
26 | flexWrap: props.wrap ? props.wrap : props.flexWrap,
27 | alignItems: props.align ? props.align : props.alignItems,
28 | justifyContent: props.justify ? props.justify : props.justifyContent,
29 | flexBasis: props.basis ? props.basis : props.flexBasis,
30 | flexGrow: props.grow ? props.grow : props.flexGrow,
31 | flexShrink: props.shrink ? props.shrink : props.flexShrink,
32 | height: props.h,
33 | width: props.w,
34 | minWidth: props.minW,
35 | minHeight: props.minH,
36 | alignSelf: props.alignSelf,
37 | maxWidth: props.maxW,
38 | maxHeight: props.maxH,
39 | opacity: props.opacity,
40 | overflow: props.overflow || 'hidden',
41 | zIndex: props.zIndex,
42 | borderStyle: props.borderStyle,
43 | backgroundColor: getThemeColor(theme.colors, props.bg as string),
44 | flex: props.flex,
45 | ...createPositionStyle(props),
46 | ...createShadowStyles(props, theme),
47 | ...createBorderWidthStyles(props),
48 | ...createSpacingStyles(props, theme.spacing),
49 | ...createBorderColorStyles(props, theme.colors),
50 | ...createBorderRadiusStyles(props, theme.borderRadius),
51 | };
52 |
53 | // merging custom style props to computed style
54 | if (props.style) {
55 | computedStyle.sectionlist = {
56 | ...computedStyle.sectionlist,
57 | // @ts-ignore
58 | ...props.style,
59 | };
60 | }
61 |
62 | return StyleSheet.create(computedStyle);
63 | };
64 |
--------------------------------------------------------------------------------
/src/components/sectionlist/sectionlist.type.tsx:
--------------------------------------------------------------------------------
1 | import type { SectionListProps as RNSectionListProps } from 'react-native';
2 |
3 | import type {
4 | BorderPropsType,
5 | SpacingPropsType,
6 | BorderRadiusPropsType,
7 | ShadowPropsType,
8 | DimensionPropsType,
9 | BackgroundPropsType,
10 | FlexPropsType,
11 | PositionPropsType,
12 | ZIndexPropsType,
13 | OverflowPropsType,
14 | OpacityPropsType,
15 | VariantPropsType,
16 | } from '../../types';
17 |
18 | export interface SectionListProps
19 | extends RNSectionListProps,
20 | BorderPropsType,
21 | SpacingPropsType,
22 | BorderRadiusPropsType,
23 | ShadowPropsType,
24 | DimensionPropsType,
25 | BackgroundPropsType,
26 | FlexPropsType,
27 | PositionPropsType,
28 | ZIndexPropsType,
29 | OverflowPropsType,
30 | OpacityPropsType,
31 | VariantPropsType {}
32 |
--------------------------------------------------------------------------------
/src/components/select/select.option.type.tsx:
--------------------------------------------------------------------------------
1 | import { ReactNode } from 'react';
2 | import { PressableProps as RNButtonProps } from 'react-native';
3 | import {
4 | BackgroundPropsType,
5 | ButtonPropsType,
6 | DimensionPropsType,
7 | DisabledPropsType,
8 | FlexPropsType,
9 | LoadingPropsType,
10 | PositionPropsType,
11 | PrefixSuffixPropsType,
12 | TextPropsType,
13 | BorderPropsType,
14 | SpacingPropsType,
15 | BorderRadiusPropsType,
16 | ShadowPropsType,
17 | VariantPropsType,
18 | } from '../../types';
19 |
20 | export interface SelectOptionProps
21 | extends RNButtonProps,
22 | BorderPropsType,
23 | SpacingPropsType,
24 | ShadowPropsType,
25 | BorderRadiusPropsType,
26 | LoadingPropsType,
27 | PositionPropsType,
28 | DisabledPropsType,
29 | FlexPropsType,
30 | ButtonPropsType,
31 | Pick,
32 | Pick,
33 | Pick,
34 | DimensionPropsType,
35 | Pick,
36 | VariantPropsType {
37 | center?: boolean;
38 | value: any;
39 | onSelect?: (value: any) => void;
40 | selectedValue?: any;
41 | children: ReactNode;
42 | }
43 |
--------------------------------------------------------------------------------
/src/components/select/select.style.tsx:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import { ThemeType } from '../../theme';
3 |
4 | import {
5 | createSpacingStyles,
6 | createBorderRadiusStyles,
7 | createBorderColorStyles,
8 | createBorderWidthStyles,
9 | getThemeColor,
10 | } from '../../theme/theme.service';
11 | import { WINDOW_HEIGHT } from '../../utilities';
12 | import { SelectProps } from './select.type';
13 |
14 | /**
15 | * computed style
16 | *
17 | * @param theme
18 | * @param props
19 | */
20 | export const getStyle = (theme: ThemeType, props: SelectProps) => {
21 | const computedStyle: any = {};
22 |
23 | computedStyle.wrapper = {
24 | backgroundColor: getThemeColor(theme.colors, props.bg as string),
25 | ...createBorderWidthStyles(props),
26 | ...createBorderColorStyles(props, theme.colors),
27 | ...createBorderRadiusStyles(props, theme.borderRadius),
28 | height: WINDOW_HEIGHT * 0.7,
29 | overflow: 'hidden',
30 | };
31 |
32 | computedStyle.indicator = {
33 | alignSelf: 'center',
34 | marginVertical: 10,
35 | };
36 |
37 | computedStyle.container = {
38 | flex: 1,
39 | ...createSpacingStyles(props, theme.spacing),
40 | };
41 |
42 | if (props.h) {
43 | computedStyle.container = {
44 | ...computedStyle.container,
45 | height: props.h,
46 | };
47 | }
48 |
49 | // merging style props to computed style
50 | if (props.style) {
51 | computedStyle.container = {
52 | ...computedStyle.container,
53 | // @ts-ignore
54 | ...props.style,
55 | };
56 | }
57 | return StyleSheet.create(computedStyle);
58 | };
59 |
--------------------------------------------------------------------------------
/src/components/select/select.type.tsx:
--------------------------------------------------------------------------------
1 | import { ViewProps as RNViewProps } from 'react-native';
2 | import {
3 | BackgroundPropsType,
4 | DimensionPropsType,
5 | FlexPropsType,
6 | PositionPropsType,
7 | BorderPropsType,
8 | SpacingPropsType,
9 | BorderRadiusPropsType,
10 | ShadowPropsType,
11 | VariantPropsType,
12 | } from '../../types';
13 | import { Option } from './select.option.component';
14 |
15 | export interface CompoundedSelect
16 | extends React.ForwardRefExoticComponent<
17 | SelectProps & React.RefAttributes
18 | > {
19 | Option: typeof Option;
20 | }
21 |
22 | export type SelectRef = {
23 | open: () => void;
24 | close: () => void;
25 | };
26 |
27 | export interface SelectProps
28 | extends RNViewProps,
29 | BorderPropsType,
30 | SpacingPropsType,
31 | BorderRadiusPropsType,
32 | ShadowPropsType,
33 | BackgroundPropsType,
34 | FlexPropsType,
35 | PositionPropsType,
36 | DimensionPropsType,
37 | VariantPropsType {
38 | title?: string | React.ReactNode;
39 | message?: string | React.ReactNode;
40 | submitText?: string;
41 | showScrollIndicator?: boolean;
42 | isMultiple?: boolean;
43 | value: any;
44 | onSelect?: (value: any) => void;
45 | submit?: boolean;
46 | data: any[];
47 | renderItem: (item: any, index: number) => React.ReactElement;
48 | keyExtractor?: (item: any, index: number) => string;
49 | renderSubmitButton?: () => React.ReactElement;
50 | }
51 |
--------------------------------------------------------------------------------
/src/components/slider/slider.component.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import RNSlider from '@react-native-community/slider';
3 |
4 | import { getStyle } from './slider.style';
5 | import type { SliderProps } from './slider.type';
6 | import { useTheme } from '../../theme/theme.hook';
7 | import { useDefaultProps } from '../../utilities/useDefaultProps';
8 | import { handleResponsiveProps } from '../../types';
9 | import { getThemeColor } from '../../theme/theme.service';
10 |
11 | const Slider: React.FunctionComponent = (incomingProps) => {
12 | const { theme, windowWidth } = useTheme();
13 | const props = useDefaultProps(
14 | 'Slider',
15 | handleResponsiveProps(incomingProps, theme, windowWidth),
16 | {
17 | flexDirection: 'column',
18 | flexWrap: 'nowrap',
19 | min: 0,
20 | max: 1,
21 | filledTrackColor: 'gray.200',
22 | colorScheme: 'blue',
23 | }
24 | );
25 |
26 | const {
27 | bg,
28 | h,
29 | w,
30 | m,
31 | mt,
32 | mr,
33 | mb,
34 | ml,
35 | ms,
36 | p,
37 | pr,
38 | pt,
39 | pb,
40 | pl,
41 | minH,
42 | minW,
43 | maxW,
44 | maxH,
45 | position,
46 | style,
47 | flexDirection,
48 | direction,
49 | children,
50 | bgImg,
51 | bgMode,
52 | alignItems,
53 | align,
54 | justifyContent,
55 | justify,
56 | flexWrap,
57 | wrap,
58 | flexGrow,
59 | grow,
60 | flexBasis,
61 | basis,
62 | flexShrink,
63 | shrink,
64 | opacity,
65 | top,
66 | left,
67 | right,
68 | bottom,
69 | zIndex,
70 | min,
71 | max,
72 | colorScheme,
73 | filledTrackColor,
74 | defaultValue,
75 | ...rest
76 | } = props;
77 | const computedStyle = getStyle(theme, props);
78 |
79 | return (
80 |
90 | );
91 | };
92 |
93 | export { Slider };
94 |
--------------------------------------------------------------------------------
/src/components/slider/slider.style.tsx:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 |
3 | import {
4 | createPositionStyle,
5 | createSpacingStyles,
6 | getThemeColor,
7 | } from '../../theme/theme.service';
8 | import type { SliderProps } from './slider.type';
9 | import type { ThemeType } from '../../theme/type';
10 |
11 | /**
12 | * computed style
13 | *
14 | * @param theme
15 | * @param props
16 | */
17 | export const getStyle = (theme: ThemeType, props: SliderProps) => {
18 | const computedStyle: any = {};
19 |
20 | computedStyle.slider = {
21 | flexDirection: props.direction ? props.direction : props.flexDirection,
22 | flexWrap: props.wrap ? props.wrap : props.flexWrap,
23 | alignItems: props.align ? props.align : props.alignItems,
24 | justifyContent: props.justify ? props.justify : props.justifyContent,
25 | flexBasis: props.basis ? props.basis : props.flexBasis,
26 | flexGrow: props.grow ? props.grow : props.flexGrow,
27 | flexShrink: props.shrink ? props.shrink : props.flexShrink,
28 | height: props.h,
29 | width: props.w,
30 | minWidth: props.minW,
31 | minHeight: props.minH,
32 | alignSelf: props.alignSelf,
33 | maxWidth: props.maxW,
34 | maxHeight: props.maxH,
35 | opacity: props.opacity,
36 | zIndex: props.zIndex,
37 | backgroundColor: getThemeColor(theme.colors, props.bg as string),
38 | flex: props.flex,
39 | ...createPositionStyle(props),
40 | ...createSpacingStyles(props, theme.spacing),
41 | };
42 |
43 | // merging custom style props to computed style
44 | if (props.style) {
45 | computedStyle.slider = {
46 | ...computedStyle.slider,
47 | // @ts-ignore
48 | ...props.style,
49 | };
50 | }
51 |
52 | return StyleSheet.create(computedStyle);
53 | };
54 |
--------------------------------------------------------------------------------
/src/components/slider/slider.type.tsx:
--------------------------------------------------------------------------------
1 | import type { ViewProps as RNViewProps } from 'react-native';
2 | import type { SliderProps as RNSliderProps } from '@react-native-community/slider';
3 |
4 | import type {
5 | SpacingPropsType,
6 | DimensionPropsType,
7 | BackgroundPropsType,
8 | FlexPropsType,
9 | PositionPropsType,
10 | ZIndexPropsType,
11 | OpacityPropsType,
12 | VariantPropsType,
13 | } from '../../types';
14 |
15 | export interface SliderProps
16 | extends RNViewProps,
17 | RNSliderProps,
18 | SpacingPropsType,
19 | DimensionPropsType,
20 | BackgroundPropsType,
21 | FlexPropsType,
22 | PositionPropsType,
23 | ZIndexPropsType,
24 | OpacityPropsType,
25 | VariantPropsType {
26 | min?: number;
27 | max?: number;
28 | defaultValue?: number;
29 | filledTrackColor?: string;
30 | colorScheme?: string;
31 | }
32 |
--------------------------------------------------------------------------------
/src/components/spinner/spinner.spec.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render } from '@testing-library/react-native';
3 |
4 | import { Spinner } from './spinner.component';
5 | import type { SpinnerProps } from './spinner.type';
6 | import { ThemeProvider } from '../../theme/theme.provider';
7 |
8 | jest.mock('react-native-toast-message', () => 'Toast');
9 |
10 | describe('Spinner component', () => {
11 | const TestSpinner: React.FC = (props) => (
12 |
13 |
14 |
15 | );
16 |
17 | it('should render component passed to children', () => {
18 | render();
19 | });
20 | });
21 |
--------------------------------------------------------------------------------
/src/components/spinner/spinner.style.tsx:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 |
3 | import {
4 | createShadowStyles,
5 | createPositionStyle,
6 | createSpacingStyles,
7 | createBorderWidthStyles,
8 | createBorderColorStyles,
9 | createBorderRadiusStyles,
10 | getThemeColor,
11 | } from '../../theme/theme.service';
12 | import type { SpinnerProps } from './spinner.type';
13 | import type { ThemeType } from '../../theme/type';
14 |
15 | /**
16 | * computed style
17 | *
18 | * @param theme
19 | * @param props
20 | */
21 | export const getStyle = (theme: ThemeType, props: SpinnerProps) => {
22 | const computedStyle: any = {};
23 |
24 | computedStyle.spinner = {
25 | flexDirection: props.direction ? props.direction : props.flexDirection,
26 | flexWrap: props.wrap ? props.wrap : props.flexWrap,
27 | alignItems: props.align ? props.align : props.alignItems,
28 | justifyContent: props.justify ? props.justify : props.justifyContent,
29 | flexBasis: props.basis ? props.basis : props.flexBasis,
30 | flexGrow: props.grow ? props.grow : props.flexGrow,
31 | flexShrink: props.shrink ? props.shrink : props.flexShrink,
32 | height: props.h,
33 | width: props.w,
34 | minWidth: props.minW,
35 | minHeight: props.minH,
36 | alignSelf: props.alignSelf,
37 | maxWidth: props.maxW,
38 | maxHeight: props.maxH,
39 | opacity: props.opacity,
40 | overflow: props.overflow || 'hidden',
41 | zIndex: props.zIndex,
42 | borderStyle: props.borderStyle,
43 | backgroundColor: getThemeColor(theme.colors, props.bg as string),
44 | flex: props.flex,
45 | ...createPositionStyle(props),
46 | ...createShadowStyles(props, theme),
47 | ...createBorderWidthStyles(props),
48 | ...createSpacingStyles(props, theme.spacing),
49 | ...createBorderColorStyles(props, theme.colors),
50 | ...createBorderRadiusStyles(props, theme.borderRadius),
51 | };
52 |
53 | // merging custom style props to computed style
54 | if (props.style) {
55 | computedStyle.spinner = {
56 | ...computedStyle.spinner,
57 | // @ts-ignore
58 | ...props.style,
59 | };
60 | }
61 |
62 | return StyleSheet.create(computedStyle);
63 | };
64 |
--------------------------------------------------------------------------------
/src/components/spinner/spinner.type.tsx:
--------------------------------------------------------------------------------
1 | import type { ViewProps as RNViewProps } from 'react-native';
2 |
3 | import type {
4 | BorderPropsType,
5 | SpacingPropsType,
6 | BorderRadiusPropsType,
7 | ShadowPropsType,
8 | DimensionPropsType,
9 | BackgroundPropsType,
10 | FlexPropsType,
11 | PositionPropsType,
12 | ActivityIndicatorPropsType,
13 | ZIndexPropsType,
14 | OverflowPropsType,
15 | OpacityPropsType,
16 | VariantPropsType,
17 | } from '../../types';
18 |
19 | export interface SpinnerProps
20 | extends RNViewProps,
21 | BorderPropsType,
22 | SpacingPropsType,
23 | BorderRadiusPropsType,
24 | ShadowPropsType,
25 | DimensionPropsType,
26 | BackgroundPropsType,
27 | FlexPropsType,
28 | PositionPropsType,
29 | ActivityIndicatorPropsType,
30 | ZIndexPropsType,
31 | OverflowPropsType,
32 | OpacityPropsType,
33 | VariantPropsType {}
34 |
--------------------------------------------------------------------------------
/src/components/stack/hstack.component.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | import type { StackProps } from './stack.type';
4 | import { useDefaultProps } from '../../utilities/useDefaultProps';
5 | import { Stack } from './stack.component';
6 | import { handleResponsiveProps } from '../../types';
7 | import { useTheme } from '../../theme';
8 |
9 | const HStack: React.FunctionComponent = (incomingProps) => {
10 | const { theme, windowWidth } = useTheme();
11 | const props = useDefaultProps(
12 | 'HStack',
13 | handleResponsiveProps(incomingProps, theme, windowWidth),
14 | {
15 | bg: 'transparent',
16 | flexDirection: 'row',
17 | flexWrap: 'nowrap',
18 | borderRadius: 'none',
19 | shadow: 'none',
20 | position: 'relative',
21 | pointerEvents: 'auto',
22 | borderStyle: 'solid',
23 | spacing: 0,
24 | }
25 | );
26 |
27 | return ;
28 | };
29 |
30 | // HStack.defaultProps = {
31 | // bg: 'transparent',
32 | // flexDirection: 'row',
33 | // flexWrap: 'nowrap',
34 | // borderRadius: 'none',
35 | // shadow: 'none',
36 | // shadowColor: 'gray900',
37 | // position: 'relative',
38 | // pointerEvents: 'auto',
39 | // borderStyle: 'solid',
40 | // spacing: 0,
41 | // };
42 |
43 | export { HStack };
44 |
--------------------------------------------------------------------------------
/src/components/stack/stack.spec.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render, screen } from '@testing-library/react-native';
3 |
4 | import { Text } from '../text/text.component';
5 | import { Stack } from './stack.component';
6 | import type { StackProps } from './stack.type';
7 | import { ThemeProvider } from '../../theme/theme.provider';
8 |
9 | jest.mock('react-native-toast-message', () => 'Toast');
10 |
11 | describe('Stack component', () => {
12 | const TestStack: React.FC = (props) => (
13 |
14 |
15 |
16 | );
17 |
18 | it('should render component passed to children', () => {
19 | render(
20 |
21 | I love Ficus UI (forked from Magnus UI)
22 | I love Ficus UI (forked from Magnus UI)
23 | I love Ficus UI (forked from Magnus UI)
24 | I love Ficus UI (forked from Magnus UI)
25 |
26 | );
27 |
28 | expect(
29 | screen.getAllByText('I love Ficus UI (forked from Magnus UI)')
30 | ).toBeTruthy();
31 | });
32 | });
33 |
--------------------------------------------------------------------------------
/src/components/stack/stack.type.tsx:
--------------------------------------------------------------------------------
1 | import type { ViewProps as RNViewProps } from 'react-native';
2 |
3 | import type {
4 | BorderPropsType,
5 | SpacingPropsType,
6 | StackSpacingPropsType,
7 | BorderRadiusPropsType,
8 | ShadowPropsType,
9 | DimensionPropsType,
10 | BackgroundPropsType,
11 | FlexPropsType,
12 | PositionPropsType,
13 | ZIndexPropsType,
14 | OverflowPropsType,
15 | OpacityPropsType,
16 | VariantPropsType,
17 | } from '../../types';
18 |
19 | export interface StackProps
20 | extends RNViewProps,
21 | BorderPropsType,
22 | SpacingPropsType,
23 | StackSpacingPropsType,
24 | BorderRadiusPropsType,
25 | ShadowPropsType,
26 | DimensionPropsType,
27 | BackgroundPropsType,
28 | FlexPropsType,
29 | PositionPropsType,
30 | ZIndexPropsType,
31 | OverflowPropsType,
32 | OpacityPropsType,
33 | VariantPropsType {}
34 |
--------------------------------------------------------------------------------
/src/components/stack/vstack.component.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | import type { StackProps } from './stack.type';
4 | import { useDefaultProps } from '../../utilities/useDefaultProps';
5 | import { Stack } from './stack.component';
6 | import { useTheme } from '../../theme';
7 | import { handleResponsiveProps } from '../../types';
8 |
9 | const VStack: React.FunctionComponent = (incomingProps) => {
10 | const { theme, windowWidth } = useTheme();
11 | const props = useDefaultProps(
12 | 'VStack',
13 | handleResponsiveProps(incomingProps, theme, windowWidth),
14 | {
15 | bg: 'transparent',
16 | flexDirection: 'column',
17 | flexWrap: 'nowrap',
18 | borderRadius: 'none',
19 | shadow: 'none',
20 | position: 'relative',
21 | pointerEvents: 'auto',
22 | borderStyle: 'solid',
23 | spacing: 0,
24 | }
25 | );
26 |
27 | return ;
28 | };
29 |
30 | // VStack.defaultProps = {
31 | // bg: 'transparent',
32 | // flexDirection: 'column',
33 | // flexWrap: 'nowrap',
34 | // borderRadius: 'none',
35 | // shadow: 'none',
36 | // shadowColor: 'gray900',
37 | // position: 'relative',
38 | // pointerEvents: 'auto',
39 | // borderStyle: 'solid',
40 | // spacing: 0,
41 | // };
42 |
43 | export { VStack };
44 |
--------------------------------------------------------------------------------
/src/components/switch/switch.style.tsx:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import { ThemeType } from '../../theme';
3 |
4 | import {
5 | createSpacingStyles,
6 | createBorderRadiusStyles,
7 | } from '../../theme/theme.service';
8 | import { SwitchProps } from './switch.type';
9 |
10 | /**
11 | * computed style
12 | *
13 | * @param theme
14 | * @param props
15 | */
16 | export const getStyle = (theme: ThemeType, props: SwitchProps) => {
17 | const computedStyle: any = {};
18 |
19 | computedStyle.container = {
20 | flexDirection: 'row',
21 | height: props.h,
22 | width: props.w,
23 | alignItems: 'center',
24 | ...createSpacingStyles(props, theme.spacing),
25 | ...createBorderRadiusStyles(props, theme.borderRadius),
26 | };
27 |
28 | computedStyle.circle = {
29 | // @ts-ignore
30 | height: props.thumbSize,
31 | // @ts-ignore
32 | width: props.thumbSize,
33 | // @ts-ignore
34 | borderRadius: Math.max(props.thumbSize / 2, 2),
35 | };
36 |
37 | // merging style props to computed style
38 | if (props.style) {
39 | computedStyle.container = {
40 | ...computedStyle.container,
41 | // @ts-ignore
42 | ...props.style,
43 | };
44 | }
45 |
46 | return StyleSheet.create(computedStyle);
47 | };
48 |
--------------------------------------------------------------------------------
/src/components/switch/switch.type.tsx:
--------------------------------------------------------------------------------
1 | import { TouchableOpacityProps as RNTouchableOpacityProps } from 'react-native';
2 |
3 | import {
4 | BackgroundPropsType,
5 | DimensionPropsType,
6 | DisabledPropsType,
7 | BorderPropsType,
8 | SpacingPropsType,
9 | BorderRadiusPropsType,
10 | VariantPropsType,
11 | } from '../../types';
12 |
13 | export interface SwitchProps
14 | extends SpacingPropsType,
15 | BorderRadiusPropsType,
16 | BorderPropsType,
17 | DisabledPropsType,
18 | Pick,
19 | Pick,
20 | Pick,
21 | DisabledPropsType,
22 | VariantPropsType {
23 | testID?: string;
24 | on?: boolean;
25 | onPress: () => void;
26 | colorScheme?: string;
27 | activeBg?: string;
28 | thumbSize?: number;
29 | thumbBg?: string;
30 | activeThumbBg?: string;
31 | duration?: number;
32 | }
33 |
--------------------------------------------------------------------------------
/src/components/text/text.component.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { Text as RNText } from 'react-native';
3 |
4 | import type { TextProps } from './text.type';
5 | import { getStyle } from './text.style';
6 | import { useDefaultProps } from '../../utilities/useDefaultProps';
7 | import { useTheme } from '../../theme/theme.hook';
8 | import { handleResponsiveProps } from '../../types';
9 |
10 | const Text: React.FunctionComponent = (incomingProps) => {
11 | const { theme, windowWidth } = useTheme();
12 | const props = useDefaultProps(
13 | 'Text',
14 | handleResponsiveProps(incomingProps, theme, windowWidth),
15 | {
16 | color: 'gray.900',
17 | textAlign: 'auto',
18 | textTransform: 'none',
19 | fontSize: 'md',
20 | overflow: 'hidden',
21 | textAlignVertical: 'center',
22 | }
23 | );
24 |
25 | const {
26 | w,
27 | h,
28 | bg,
29 | m,
30 | mt,
31 | mr,
32 | mb,
33 | ml,
34 | ms,
35 | p,
36 | pr,
37 | pt,
38 | pb,
39 | pl,
40 | flex,
41 | minH,
42 | minW,
43 | color,
44 | fontSize,
45 | children,
46 | textAlign,
47 | fontWeight,
48 | lineHeight,
49 | letterSpacing,
50 | textTransform,
51 | textDecorColor,
52 | textDecorStyle,
53 | fontStyle,
54 | textDecorLine,
55 | textAlignVertical,
56 | overflow,
57 | opacity,
58 | zIndex,
59 | style,
60 | ...rest
61 | } = props;
62 | const computedStyle = getStyle(theme, props);
63 |
64 | return (
65 |
66 | {children}
67 |
68 | );
69 | };
70 |
71 | // Text.defaultProps = {
72 | // color: 'gray.900',
73 | // textAlign: 'auto',
74 | // textTransform: 'none',
75 | // fontSize: 'md',
76 | // overflow: 'hidden',
77 | // };
78 |
79 | export { Text };
80 |
--------------------------------------------------------------------------------
/src/components/text/text.type.ts:
--------------------------------------------------------------------------------
1 | import type { TextProps as RNTextProps } from 'react-native';
2 | import type {
3 | BackgroundPropsType,
4 | DimensionPropsType,
5 | FlexPropsType,
6 | OpacityPropsType,
7 | OverflowPropsType,
8 | TextPropsType,
9 | ZIndexPropsType,
10 | BorderPropsType,
11 | SpacingPropsType,
12 | BorderRadiusPropsType,
13 | VariantPropsType,
14 | } from '../../types';
15 |
16 | export interface TextProps
17 | extends RNTextProps,
18 | SpacingPropsType,
19 | BorderRadiusPropsType,
20 | BorderPropsType,
21 | TextPropsType,
22 | DimensionPropsType,
23 | OverflowPropsType,
24 | OpacityPropsType,
25 | ZIndexPropsType,
26 | Partial>,
27 | Partial>,
28 | VariantPropsType {}
29 |
--------------------------------------------------------------------------------
/src/components/touchable-highlight/touchable-highlight.spec.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render, screen } from '@testing-library/react-native';
3 |
4 | import { Text } from '../text/text.component';
5 | import { TouchableHighlight } from './touchable-highlight.component';
6 | import type { TouchableHighlightProps } from './touchable-highlight.type';
7 | import { ThemeProvider } from '../../theme/theme.provider';
8 |
9 | jest.mock('react-native-toast-message', () => 'Toast');
10 |
11 | describe('TouchableHighlight component', () => {
12 | const TestTouchableHighlight: React.FC = (props) => (
13 |
14 |
15 |
16 | );
17 |
18 | it('should render component passed to children', () => {
19 | render(
20 |
21 | I love Ficus UI (forked from Magnus UI)
22 |
23 | );
24 |
25 | expect(
26 | screen.getByText('I love Ficus UI (forked from Magnus UI)')
27 | ).toBeTruthy();
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/src/components/touchable-highlight/touchable-highlight.style.tsx:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 |
3 | import {
4 | createShadowStyles,
5 | createPositionStyle,
6 | createSpacingStyles,
7 | createBorderWidthStyles,
8 | createBorderColorStyles,
9 | createBorderRadiusStyles,
10 | getThemeColor,
11 | } from '../../theme/theme.service';
12 | import type { TouchableHighlightProps } from './touchable-highlight.type';
13 | import type { ThemeType } from '../../theme/type';
14 |
15 | /**
16 | * computed style
17 | *
18 | * @param theme
19 | * @param props
20 | */
21 | export const getStyle = (theme: ThemeType, props: TouchableHighlightProps) => {
22 | const computedStyle: any = {};
23 |
24 | computedStyle.touchable = {
25 | flexDirection: props.direction ? props.direction : props.flexDirection,
26 | flexWrap: props.wrap ? props.wrap : props.flexWrap,
27 | alignItems: props.align ? props.align : props.alignItems,
28 | justifyContent: props.justify ? props.justify : props.justifyContent,
29 | flexBasis: props.basis ? props.basis : props.flexBasis,
30 | flexGrow: props.grow ? props.grow : props.flexGrow,
31 | flexShrink: props.shrink ? props.shrink : props.flexShrink,
32 | height: props.h,
33 | width: props.w,
34 | minWidth: props.minW,
35 | minHeight: props.minH,
36 | alignSelf: props.alignSelf,
37 | maxWidth: props.maxW,
38 | maxHeight: props.maxH,
39 | opacity: props.opacity,
40 | overflow: props.overflow || 'hidden',
41 | zIndex: props.zIndex,
42 | borderStyle: props.borderStyle,
43 | backgroundColor: getThemeColor(theme.colors, props.bg as string),
44 | flex: props.flex,
45 | ...createPositionStyle(props),
46 | ...createShadowStyles(props, theme),
47 | ...createBorderWidthStyles(props),
48 | ...createSpacingStyles(props, theme.spacing),
49 | ...createBorderColorStyles(props, theme.colors),
50 | ...createBorderRadiusStyles(props, theme.borderRadius),
51 | };
52 |
53 | // merging custom style props to computed style
54 | if (props.style) {
55 | computedStyle.touchable = {
56 | ...computedStyle.touchable,
57 | // @ts-ignore
58 | ...props.style,
59 | };
60 | }
61 |
62 | return StyleSheet.create(computedStyle);
63 | };
64 |
--------------------------------------------------------------------------------
/src/components/touchable-highlight/touchable-highlight.type.tsx:
--------------------------------------------------------------------------------
1 | import type { TouchableHighlightProps as RNTouchableHighlightProps } from 'react-native';
2 |
3 | import type {
4 | BorderPropsType,
5 | SpacingPropsType,
6 | BorderRadiusPropsType,
7 | ShadowPropsType,
8 | DimensionPropsType,
9 | BackgroundPropsType,
10 | FlexPropsType,
11 | PositionPropsType,
12 | ZIndexPropsType,
13 | OverflowPropsType,
14 | OpacityPropsType,
15 | VariantPropsType,
16 | } from '../../types';
17 |
18 | export interface TouchableHighlightProps
19 | extends RNTouchableHighlightProps,
20 | BorderPropsType,
21 | SpacingPropsType,
22 | BorderRadiusPropsType,
23 | ShadowPropsType,
24 | DimensionPropsType,
25 | BackgroundPropsType,
26 | FlexPropsType,
27 | PositionPropsType,
28 | ZIndexPropsType,
29 | OverflowPropsType,
30 | OpacityPropsType,
31 | VariantPropsType {}
32 |
--------------------------------------------------------------------------------
/src/components/touchable-opacity/touchable-opacity.spec.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render, screen } from '@testing-library/react-native';
3 |
4 | import { Text } from '../text/text.component';
5 | import { TouchableOpacity } from './touchable-opacity.component';
6 | import type { TouchableOpacityProps } from './touchable-opacity.type';
7 | import { ThemeProvider } from '../../theme/theme.provider';
8 |
9 | jest.mock('react-native-toast-message', () => 'Toast');
10 |
11 | describe('TouchableOpacity component', () => {
12 | const TestTouchableOpacity: React.FC = (props) => (
13 |
14 |
15 |
16 | );
17 |
18 | it('should render component passed to children', () => {
19 | render(
20 |
21 | I love Ficus UI (forked from Magnus UI)
22 |
23 | );
24 |
25 | expect(
26 | screen.getByText('I love Ficus UI (forked from Magnus UI)')
27 | ).toBeTruthy();
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/src/components/touchable-opacity/touchable-opacity.style.tsx:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 |
3 | import {
4 | createShadowStyles,
5 | createPositionStyle,
6 | createSpacingStyles,
7 | createBorderWidthStyles,
8 | createBorderColorStyles,
9 | createBorderRadiusStyles,
10 | getThemeColor,
11 | } from '../../theme/theme.service';
12 | import type { TouchableOpacityProps } from './touchable-opacity.type';
13 | import type { ThemeType } from '../../theme/type';
14 |
15 | /**
16 | * computed style
17 | *
18 | * @param theme
19 | * @param props
20 | */
21 | export const getStyle = (theme: ThemeType, props: TouchableOpacityProps) => {
22 | const computedStyle: any = {};
23 |
24 | computedStyle.touchable = {
25 | flexDirection: props.direction ? props.direction : props.flexDirection,
26 | flexWrap: props.wrap ? props.wrap : props.flexWrap,
27 | alignItems: props.align ? props.align : props.alignItems,
28 | justifyContent: props.justify ? props.justify : props.justifyContent,
29 | flexBasis: props.basis ? props.basis : props.flexBasis,
30 | flexGrow: props.grow ? props.grow : props.flexGrow,
31 | flexShrink: props.shrink ? props.shrink : props.flexShrink,
32 | height: props.h,
33 | width: props.w,
34 | minWidth: props.minW,
35 | minHeight: props.minH,
36 | alignSelf: props.alignSelf,
37 | maxWidth: props.maxW,
38 | maxHeight: props.maxH,
39 | opacity: props.opacity,
40 | overflow: props.overflow || 'hidden',
41 | zIndex: props.zIndex,
42 | borderStyle: props.borderStyle,
43 | backgroundColor: getThemeColor(theme.colors, props.bg as string),
44 | flex: props.flex,
45 | ...createPositionStyle(props),
46 | ...createShadowStyles(props, theme),
47 | ...createBorderWidthStyles(props),
48 | ...createSpacingStyles(props, theme.spacing),
49 | ...createBorderColorStyles(props, theme.colors),
50 | ...createBorderRadiusStyles(props, theme.borderRadius),
51 | };
52 |
53 | // merging custom style props to computed style
54 | if (props.style) {
55 | computedStyle.touchable = {
56 | ...computedStyle.touchable,
57 | // @ts-ignore
58 | ...props.style,
59 | };
60 | }
61 |
62 | return StyleSheet.create(computedStyle);
63 | };
64 |
--------------------------------------------------------------------------------
/src/components/touchable-opacity/touchable-opacity.type.tsx:
--------------------------------------------------------------------------------
1 | import type { TouchableOpacityProps as RNTouchableOpacityProps } from 'react-native';
2 |
3 | import type {
4 | BorderPropsType,
5 | SpacingPropsType,
6 | BorderRadiusPropsType,
7 | ShadowPropsType,
8 | DimensionPropsType,
9 | BackgroundPropsType,
10 | FlexPropsType,
11 | PositionPropsType,
12 | ZIndexPropsType,
13 | OverflowPropsType,
14 | OpacityPropsType,
15 | VariantPropsType,
16 | } from '../../types';
17 |
18 | export interface TouchableOpacityProps
19 | extends RNTouchableOpacityProps,
20 | BorderPropsType,
21 | SpacingPropsType,
22 | BorderRadiusPropsType,
23 | ShadowPropsType,
24 | DimensionPropsType,
25 | BackgroundPropsType,
26 | FlexPropsType,
27 | PositionPropsType,
28 | ZIndexPropsType,
29 | OverflowPropsType,
30 | OpacityPropsType,
31 | VariantPropsType {}
32 |
--------------------------------------------------------------------------------
/src/components/touchable-without-feedback/touchable-without-feedback.spec.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render, screen } from '@testing-library/react-native';
3 |
4 | import { Text } from '../text/text.component';
5 | import { TouchableWithoutFeedback } from './touchable-without-feedback.component';
6 | import type { TouchableWithoutFeedbackProps } from './touchable-without-feedback.type';
7 | import { ThemeProvider } from '../../theme/theme.provider';
8 |
9 | jest.mock('react-native-toast-message', () => 'Toast');
10 |
11 | describe('TouchableWithoutFeedback component', () => {
12 | const TestTouchableWithoutFeedback: React.FC = (
13 | props
14 | ) => (
15 |
16 |
17 |
18 | );
19 |
20 | it('should render component passed to children', () => {
21 | render(
22 |
23 | I love Ficus UI (forked from Magnus UI)
24 |
25 | );
26 |
27 | expect(
28 | screen.getByText('I love Ficus UI (forked from Magnus UI)')
29 | ).toBeTruthy();
30 | });
31 | });
32 |
--------------------------------------------------------------------------------
/src/components/touchable-without-feedback/touchable-without-feedback.type.tsx:
--------------------------------------------------------------------------------
1 | import type { TouchableWithoutFeedbackProps as RNTouchableWithoutFeedbackProps } from 'react-native';
2 |
3 | import type {
4 | BorderPropsType,
5 | SpacingPropsType,
6 | BorderRadiusPropsType,
7 | ShadowPropsType,
8 | DimensionPropsType,
9 | BackgroundPropsType,
10 | FlexPropsType,
11 | PositionPropsType,
12 | ZIndexPropsType,
13 | OverflowPropsType,
14 | OpacityPropsType,
15 | VariantPropsType,
16 | } from '../../types';
17 |
18 | export interface TouchableWithoutFeedbackProps
19 | extends RNTouchableWithoutFeedbackProps,
20 | BorderPropsType,
21 | SpacingPropsType,
22 | BorderRadiusPropsType,
23 | ShadowPropsType,
24 | DimensionPropsType,
25 | BackgroundPropsType,
26 | FlexPropsType,
27 | PositionPropsType,
28 | ZIndexPropsType,
29 | OverflowPropsType,
30 | OpacityPropsType,
31 | VariantPropsType {}
32 |
--------------------------------------------------------------------------------
/src/hooks/index.ts:
--------------------------------------------------------------------------------
1 | export { useToast } from './toast/useToast';
2 | export { useDisclosure } from './utils/useDisclosure';
3 | export { useMediaQuery } from './responsive/useMediaQuery';
4 |
--------------------------------------------------------------------------------
/src/hooks/responsive/useMediaQuery.tsx:
--------------------------------------------------------------------------------
1 | import { useWindowDimensions } from 'react-native';
2 |
3 | type MediaQueryRange = {
4 | minWidth?: number;
5 | maxWidth?: number;
6 | };
7 |
8 | type MediaQueryArray = MediaQueryRange[];
9 |
10 | const useMediaQuery = (...widths: MediaQueryArray) => {
11 | const { width } = useWindowDimensions();
12 |
13 | return widths.map((givenWidth) => {
14 | if (givenWidth?.minWidth && givenWidth?.maxWidth) {
15 | return width >= givenWidth?.minWidth && width < givenWidth?.maxWidth;
16 | }
17 |
18 | if (givenWidth?.minWidth && !givenWidth?.maxWidth) {
19 | return width >= givenWidth?.minWidth;
20 | }
21 |
22 | if (!givenWidth?.minWidth && givenWidth?.maxWidth) {
23 | return width < givenWidth?.maxWidth;
24 | }
25 |
26 | return false;
27 | });
28 | };
29 |
30 | export { useMediaQuery };
31 |
--------------------------------------------------------------------------------
/src/hooks/toast/useToast.tsx:
--------------------------------------------------------------------------------
1 | import Toast from 'react-native-toast-message';
2 |
3 | const useToast = () => {
4 | const { show, hide } = Toast;
5 | return { show, hide, Toast };
6 | };
7 |
8 | export { useToast };
9 |
--------------------------------------------------------------------------------
/src/hooks/utils/useDisclosure.tsx:
--------------------------------------------------------------------------------
1 | import { useState } from 'react';
2 |
3 | const useDisclosure = () => {
4 | const [isOpen, setIsOpen] = useState(false);
5 |
6 | const onOpen = () => {
7 | setIsOpen(true);
8 | };
9 |
10 | const onClose = () => {
11 | setIsOpen(false);
12 | };
13 |
14 | return { isOpen, onOpen, onClose };
15 | };
16 |
17 | export { useDisclosure };
18 |
--------------------------------------------------------------------------------
/src/index.tsx:
--------------------------------------------------------------------------------
1 | export * from './theme';
2 | export * from './components';
3 | export * from './utilities';
4 | export * from './hooks';
5 |
--------------------------------------------------------------------------------
/src/theme/index.ts:
--------------------------------------------------------------------------------
1 | export { ThemeContext } from './theme.context';
2 | export { ThemeProvider, ThemeProviderProps } from './theme.provider';
3 | export { getThemeProperty } from './theme.service';
4 | export { useTheme } from './theme.hook';
5 | export { ThemeType } from './type';
6 | export { defaultTheme } from './theme.default';
7 |
--------------------------------------------------------------------------------
/src/theme/theme.context.ts:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import type { ThemeType } from './type';
3 | import { defaultTheme } from './theme.default';
4 |
5 | export interface ThemeContextType {
6 | theme: ThemeType;
7 | setTheme: (theme: ThemeType) => void;
8 | windowWidth: number;
9 | }
10 |
11 | export const ThemeContext: React.Context = React.createContext(
12 | {
13 | theme: defaultTheme,
14 | setTheme: (_theme: ThemeType) => {},
15 | windowWidth: 0,
16 | }
17 | );
18 |
--------------------------------------------------------------------------------
/src/theme/theme.hook.ts:
--------------------------------------------------------------------------------
1 | import { useContext } from 'react';
2 |
3 | import { ThemeContext, ThemeContextType } from './theme.context';
4 |
5 | export const useTheme = (): ThemeContextType => {
6 | const themeContext = useContext(ThemeContext);
7 | return themeContext;
8 | };
9 |
--------------------------------------------------------------------------------
/src/theme/theme.provider.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | import { ThemeContext } from './theme.context';
4 | import deepmerge from 'deepmerge';
5 | import type { ThemeType } from './type';
6 | import { defaultTheme } from './theme.default';
7 | import Toast from 'react-native-toast-message';
8 | import { useWindowDimensions } from 'react-native';
9 | import { GestureHandlerRootView } from 'react-native-gesture-handler';
10 | import { BottomSheetModalProvider } from '@gorhom/bottom-sheet';
11 |
12 | export interface ThemeProviderProps {
13 | theme?: ThemeType;
14 | children: React.ReactNode;
15 | }
16 |
17 | export const ThemeProvider: React.FunctionComponent = (
18 | props
19 | ) => {
20 | const { theme: themeProp = {}, children } = props;
21 | const { width } = useWindowDimensions();
22 |
23 | const [themeState, setThemeState] = React.useState(
24 | deepmerge(defaultTheme, themeProp)
25 | );
26 |
27 | const setTheme = (newTheme: ThemeType) => {
28 | const mergedTheme = deepmerge(defaultTheme, newTheme);
29 | setThemeState(mergedTheme);
30 | };
31 |
32 | return (
33 | // eslint-disable-next-line react-native/no-inline-styles
34 |
35 |
38 |
39 | {children}
40 |
41 |
42 |
43 |
44 | );
45 | };
46 |
--------------------------------------------------------------------------------
/src/utilities/useDefaultProps.ts:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import type { DefaultProps, VariantPropsType } from '../types';
3 | import { useTheme } from '../theme/theme.hook';
4 | import type { ThemeType } from '../theme/type';
5 |
6 | export const useDefaultProps = (
7 | componentName: keyof NonNullable | null,
8 | props: Props & VariantPropsType,
9 | defaultProps: DefaultProps
10 | ) => {
11 | const { theme } = useTheme();
12 |
13 | const finalProps = React.useMemo(() => {
14 | if (!componentName) {
15 | return {
16 | ...defaultProps,
17 | ...props,
18 | };
19 | }
20 |
21 | let propsFromTheme = {
22 | ...(theme.components?.[componentName] ?? {}),
23 | ...(props.variant &&
24 | (theme.components?.[componentName]?.variants?.[
25 | props.variant as string
26 | ] ??
27 | {})),
28 | };
29 |
30 | delete propsFromTheme.variants;
31 |
32 | const mergedProps = {
33 | ...defaultProps,
34 | ...propsFromTheme,
35 | ...props,
36 | };
37 |
38 | return mergedProps;
39 | }, [componentName, defaultProps, props, theme.components]);
40 |
41 | return finalProps as Props & Required;
42 | };
43 |
--------------------------------------------------------------------------------
/src/utilities/withDefaultProps.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { ThemeType } from '../theme/type';
3 | import { ThemeContext } from '../theme/theme.context';
4 | import { DefaultProps, VariantPropsType } from '../types';
5 |
6 | export function withDefaultProps<
7 | Props extends object,
8 | Defaults extends DefaultProps = {}
9 | >(
10 | WrappedComponent: React.ComponentClass,
11 | componentName: keyof NonNullable,
12 | defaultProps: Defaults
13 | ) {
14 | type Variant = Props & VariantPropsType;
15 | return class extends React.PureComponent {
16 | static contextType = ThemeContext;
17 | // using `declare` requires babel plugin which doesn't seem to work
18 | // class related components & HOC's should be refactored anyway
19 | // @ts-ignore
20 | context!: React.ContextType;
21 |
22 | render() {
23 | const theme = this.context.theme;
24 |
25 | if (!componentName) {
26 | return ;
27 | }
28 |
29 | let propsFromTheme = {
30 | ...(theme.components?.[componentName] ?? {}),
31 | ...(this.props.variant &&
32 | //@ts-ignore
33 | (theme.components?.[componentName]?.variants?.[this.props.variant] ??
34 | {})),
35 | };
36 |
37 | delete propsFromTheme.variants;
38 |
39 | const mergedProps = {
40 | ...defaultProps,
41 | ...propsFromTheme,
42 | ...this.props,
43 | };
44 |
45 | return ;
46 | }
47 | };
48 | }
49 |
--------------------------------------------------------------------------------
/tsconfig.build.json:
--------------------------------------------------------------------------------
1 |
2 | {
3 | "extends": "./tsconfig",
4 | "exclude": ["example"]
5 | }
6 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": "src",
4 | "paths": {
5 | "react-native-ficus-ui": ["./src/index"]
6 | },
7 | "allowUnreachableCode": false,
8 | "allowUnusedLabels": false,
9 | "esModuleInterop": true,
10 | "forceConsistentCasingInFileNames": true,
11 | "jsx": "react",
12 | "lib": ["esnext"],
13 | "module": "esnext",
14 | "moduleResolution": "node",
15 | "noFallthroughCasesInSwitch": true,
16 | "noImplicitReturns": true,
17 | "noImplicitUseStrict": false,
18 | "noStrictGenericChecks": false,
19 | "noUnusedLocals": true,
20 | "noUnusedParameters": true,
21 | "resolveJsonModule": true,
22 | "skipLibCheck": true,
23 | "strict": true,
24 | "target": "esnext",
25 | "types": ["react-native", "jest", "@testing-library/jest-native"]
26 | },
27 | "include": ["src"]
28 | }
29 |
--------------------------------------------------------------------------------