= (
9 | incomingProps
10 | ) => {
11 | const props = useDefaultProps('AvatarGroup', incomingProps, {
12 | row: true,
13 | ml: 'none',
14 | offset: 'lg',
15 | });
16 |
17 | const { children, ml, offset, ...rest } = props;
18 | const { theme } = useTheme();
19 | const calculatedOffset = getThemeProperty(theme.spacing, offset);
20 | const calculatedMarginLeft = getThemeProperty(theme.spacing, ml);
21 |
22 | return (
23 |
24 | {React.Children.map(children, (child: React.ReactElement) => {
25 | return React.cloneElement(child, {
26 | ml: -1 * calculatedOffset,
27 | });
28 | })}
29 |
30 | );
31 | };
32 |
33 | // AvatarGroup.defaultProps = {
34 | // row: true,
35 | // ml: 'none',
36 | // offset: 'lg',
37 | // };
38 |
39 | export { AvatarGroup };
40 |
--------------------------------------------------------------------------------
/src/ui/avatar/avatar.group.type.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | BackgroundPropsType,
3 | DimensionPropsType,
4 | FlexPropsType,
5 | OpacityPropsType,
6 | OverflowPropsType,
7 | PositionPropsType,
8 | ZIndexPropsType,
9 | BorderPropsType,
10 | SpacingPropsType,
11 | RoundedPropsType,
12 | ShadowPropsType,
13 | } from '../../types';
14 |
15 | export interface AvatarGroupProps
16 | extends BorderPropsType,
17 | SpacingPropsType,
18 | RoundedPropsType,
19 | ShadowPropsType,
20 | DimensionPropsType,
21 | BackgroundPropsType,
22 | FlexPropsType,
23 | PositionPropsType,
24 | OverflowPropsType,
25 | OpacityPropsType,
26 | ZIndexPropsType {
27 | offset?: string | number;
28 | children: React.ReactElement[] | React.ReactElement;
29 | }
30 |
--------------------------------------------------------------------------------
/src/ui/avatar/avatar.type.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | ViewProps as RNViewProps,
3 | ImageSourcePropType as RNImageSourcePropType,
4 | } from 'react-native';
5 |
6 | import { AvatarGroup } from './avatar.group.component';
7 | import {
8 | BorderPropsType,
9 | SpacingPropsType,
10 | RoundedPropsType,
11 | ShadowPropsType,
12 | BackgroundPropsType,
13 | FlexPropsType,
14 | OpacityPropsType,
15 | PositionPropsType,
16 | TextPropsType,
17 | ZIndexPropsType,
18 | VariantPropsType,
19 | } from '../../types';
20 |
21 | export type CompoundedAvatar = React.FunctionComponent
& {
22 | Group: typeof AvatarGroup;
23 | };
24 |
25 | export interface AvatarProps
26 | extends RNViewProps,
27 | BorderPropsType,
28 | SpacingPropsType,
29 | RoundedPropsType,
30 | ShadowPropsType,
31 | PositionPropsType,
32 | ZIndexPropsType,
33 | OpacityPropsType,
34 | Pick,
35 | Pick,
36 | Pick,
37 | VariantPropsType {
38 | size?: number;
39 | source?: RNImageSourcePropType;
40 | }
41 |
--------------------------------------------------------------------------------
/src/ui/badge/badge.style.tsx:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import { ThemeType } from '../../theme';
3 |
4 | import {
5 | createShadowStyles,
6 | createSpacingStyles,
7 | createBorderWidthStyles,
8 | createBorderColorStyles,
9 | createBorderRadiusStyles,
10 | createPositionStyle,
11 | getThemeColor,
12 | } from '../../theme/theme.service';
13 | import { BadgeProps } from './badge.type';
14 |
15 | /**
16 | * computed style
17 | *
18 | * @param theme
19 | * @param props
20 | */
21 | export const getStyle = (
22 | theme: ThemeType,
23 | props: React.PropsWithChildren
24 | ) => {
25 | const computedStyle: any = {};
26 |
27 | computedStyle.container = {
28 | alignSelf: props.alignSelf,
29 | minHeight: typeof props.count === 'undefined' ? 10 : 30,
30 | minWidth: typeof props.count === 'undefined' ? 10 : 30,
31 | };
32 |
33 | computedStyle.div = {
34 | zIndex: 1,
35 | height: props.h,
36 | width: props.w,
37 | alignItems: 'center',
38 | justifyContent: 'center',
39 | alignSelf: 'flex-start',
40 | opacity: props.opacity,
41 | minHeight: typeof props.children === 'string' ? 30 : 10,
42 | backgroundColor: getThemeColor(theme.colors, props.bg),
43 | minWidth: typeof props.children === 'string' ? 30 : 10,
44 | ...createPositionStyle(props),
45 | ...createBorderWidthStyles(props),
46 | ...createShadowStyles(props, theme),
47 | ...createSpacingStyles(props, theme.spacing),
48 | ...createBorderColorStyles(props, theme.colors),
49 | ...createBorderRadiusStyles(props, theme.borderRadius),
50 | position: typeof props.children !== 'string' ? 'absolute' : props.position,
51 | };
52 |
53 | computedStyle.text = {
54 | paddingHorizontal: 10,
55 | };
56 |
57 | // merging style props to computed style
58 | if (props.style) {
59 | computedStyle.div = {
60 | ...computedStyle.div,
61 | // @ts-ignore
62 | ...props.style,
63 | };
64 | }
65 |
66 | return StyleSheet.create(computedStyle);
67 | };
68 |
--------------------------------------------------------------------------------
/src/ui/badge/badge.type.tsx:
--------------------------------------------------------------------------------
1 | import { ViewProps as RNViewProps } from 'react-native';
2 | import {
3 | DimensionPropsType,
4 | FlexPropsType,
5 | OpacityPropsType,
6 | PositionPropsType,
7 | TextPropsType,
8 | ZIndexPropsType,
9 | BorderPropsType,
10 | SpacingPropsType,
11 | RoundedPropsType,
12 | ShadowPropsType,
13 | BackgroundPropsType,
14 | VariantPropsType,
15 | } from '../../types';
16 |
17 | export interface BadgeProps
18 | extends RNViewProps,
19 | BorderPropsType,
20 | SpacingPropsType,
21 | RoundedPropsType,
22 | ShadowPropsType,
23 | DimensionPropsType,
24 | PositionPropsType,
25 | OpacityPropsType,
26 | ZIndexPropsType,
27 | Pick,
28 | Pick,
29 | Pick,
30 | VariantPropsType {
31 | count?: string | number;
32 | }
33 |
--------------------------------------------------------------------------------
/src/ui/button/button.service.ts:
--------------------------------------------------------------------------------
1 | import color from 'color';
2 |
3 | import { getThemeColor } from '../../theme/theme.service';
4 | import { ButtonProps } from './button.type';
5 | import { ThemeType } from '../../theme/type';
6 |
7 | /**
8 | * returns underlay color
9 | *
10 | * @param theme
11 | * @param props
12 | */
13 | export const getUnderlayColor = (theme: ThemeType, props: ButtonProps) => {
14 | return getThemeColor(
15 | theme.colors,
16 | props.underlayColor
17 | ? props.underlayColor
18 | : color(getThemeColor(theme.colors, props.bg)).darken(0.1).rgb().string()
19 | );
20 | };
21 |
22 | /**
23 | * return ripple color
24 | *
25 | * @param theme
26 | * @param props
27 | */
28 | export const getRippleColor = (theme: ThemeType, props: ButtonProps) => {
29 | return color(getThemeColor(theme.colors, props.rippleColor))
30 | .alpha(props.disabled ? 0 : 0.2)
31 | .rgb()
32 | .string();
33 | };
34 |
--------------------------------------------------------------------------------
/src/ui/button/button.type.ts:
--------------------------------------------------------------------------------
1 | import { PressableProps as RNButtonProps } from 'react-native';
2 | import {
3 | ButtonPropsType,
4 | DimensionPropsType,
5 | DisabledPropsType,
6 | FlexPropsType,
7 | LoadingPropsType,
8 | OpacityPropsType,
9 | PositionPropsType,
10 | PrefixSuffixPropsType,
11 | TextPropsType,
12 | ZIndexPropsType,
13 | BackgroundPropsType,
14 | BorderPropsType,
15 | SpacingPropsType,
16 | RoundedPropsType,
17 | ShadowPropsType,
18 | VariantPropsType,
19 | } from '../../types';
20 |
21 | export interface ButtonProps
22 | extends RNButtonProps,
23 | BorderPropsType,
24 | SpacingPropsType,
25 | ShadowPropsType,
26 | RoundedPropsType,
27 | DimensionPropsType,
28 | PositionPropsType,
29 | FlexPropsType,
30 | LoadingPropsType,
31 | PrefixSuffixPropsType,
32 | DisabledPropsType,
33 | TextPropsType,
34 | OpacityPropsType,
35 | ZIndexPropsType,
36 | ButtonPropsType,
37 | Pick,
38 | VariantPropsType {}
39 |
--------------------------------------------------------------------------------
/src/ui/carousel/carousel.type.tsx:
--------------------------------------------------------------------------------
1 | import { ReactNode } from 'react';
2 | import {
3 | FlexPropsType,
4 | BorderPropsType,
5 | RoundedPropsType,
6 | ShadowPropsType,
7 | SpacingPropsType,
8 | VariantPropsType,
9 | } from '../../types';
10 |
11 | import CarouselItem from './item.carousel';
12 |
13 | interface CarouselIndicator {
14 | selectedPage: number;
15 | totalPages: number;
16 | }
17 |
18 | export interface CarouselProps
19 | extends BorderPropsType,
20 | RoundedPropsType,
21 | ShadowPropsType,
22 | SpacingPropsType,
23 | Pick,
24 | VariantPropsType {
25 | showIndicators?: boolean;
26 | renderIndicators?: (props: CarouselIndicator) => JSX.Element;
27 | children: ReactNode;
28 | }
29 |
30 | export interface CompoundedCarousel extends React.FC {
31 | Item: typeof CarouselItem;
32 | }
33 |
--------------------------------------------------------------------------------
/src/ui/carousel/item.carousel.tsx:
--------------------------------------------------------------------------------
1 | import React, { ReactNode } from 'react';
2 |
3 | interface CarouselItemProps {
4 | children: ReactNode;
5 | }
6 |
7 | const CarouselItem = ({ children }: CarouselItemProps) => {
8 | return <>{children}>;
9 | };
10 |
11 | export default CarouselItem;
12 |
--------------------------------------------------------------------------------
/src/ui/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 | LoadingPropsType,
9 | OpacityPropsType,
10 | PositionPropsType,
11 | PrefixSuffixPropsType,
12 | TextPropsType,
13 | ZIndexPropsType,
14 | BorderPropsType,
15 | SpacingPropsType,
16 | RoundedPropsType,
17 | ShadowPropsType,
18 | VariantPropsType,
19 | } from '../../types';
20 | import { DivProps } from '../div/div.type';
21 | import { CheckboxGroup } from './group.component';
22 |
23 | export type CompundedCheckbox = React.FunctionComponent
& {
24 | Group: typeof CheckboxGroup;
25 | };
26 |
27 | export interface CheckboxProps
28 | extends Omit,
29 | BorderPropsType,
30 | SpacingPropsType,
31 | ShadowPropsType,
32 | RoundedPropsType,
33 | DimensionPropsType,
34 | PositionPropsType,
35 | FlexPropsType,
36 | LoadingPropsType,
37 | PrefixSuffixPropsType,
38 | OpacityPropsType,
39 | ZIndexPropsType,
40 | DisabledPropsType,
41 | Pick,
42 | Pick,
43 | ButtonPropsType,
44 | VariantPropsType {
45 | highlightBg?: string;
46 | activeColor?: string;
47 | inactiveColor?: string;
48 | defaultChecked?: boolean;
49 | activeIcon?: string | React.ReactNode;
50 | inactiveIcon?: string | React.ReactNode;
51 | checked?: boolean;
52 | onChecked?: (newValue: boolean) => void;
53 | onChange?: (value: any) => void;
54 | value?: any;
55 | children?: ((states: CheckboxStates) => React.ReactNode) | React.ReactNode;
56 | }
57 |
58 | export interface CheckboxGroupProps extends DivProps {
59 | onChange?: (value: any[]) => void;
60 | value?: any[];
61 | defaultValue?: any[];
62 | children: React.ReactElement[] | React.ReactElement;
63 | }
64 |
65 | export interface CheckboxStates {
66 | focussed?: boolean;
67 | checked?: boolean;
68 | disabled?: boolean;
69 | loading?: boolean;
70 | }
71 |
--------------------------------------------------------------------------------
/src/ui/checkbox/group.component.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { useState } from 'react';
3 | import { useDefaultProps } from '../../utilities/useDefaultProps';
4 |
5 | import { Div } from '../div/div.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 | ...rest
19 | } = props;
20 |
21 | /**
22 | * checks if checked value is already in the state or not,
23 | * if it, remove it else add it
24 | *
25 | * @param value
26 | */
27 | const onChange = (optionValue: any) => {
28 | const optionIndex = value.indexOf(optionValue);
29 | const newValue = [...value];
30 |
31 | if (optionIndex === -1) {
32 | newValue.push(optionValue);
33 | } else {
34 | newValue.splice(optionIndex, 1);
35 | }
36 |
37 | if (!('value' in props)) {
38 | setValue(newValue);
39 | }
40 |
41 | if (onChangeProp) {
42 | onChangeProp(newValue);
43 | }
44 | };
45 |
46 | /**
47 | * clones the children and add checked, onChange prop
48 | */
49 | const renderChildren = () => {
50 | return React.Children.map(children, (child: React.ReactElement) => {
51 | return React.cloneElement(child, {
52 | onChange,
53 | checked: value.indexOf(child.props.value) > -1,
54 | });
55 | });
56 | };
57 |
58 | return {renderChildren()}
;
59 | };
60 |
61 | export { CheckboxGroup };
62 |
--------------------------------------------------------------------------------
/src/ui/collapse/collapse.type.tsx:
--------------------------------------------------------------------------------
1 | import { DivProps } from '../div/div.type';
2 | import { ButtonProps } from '../button/button.type';
3 | import { CollapseBody } from './collapse.body.component';
4 | import { CollapseHeader } from './collapse.header.component';
5 | import { CollapseGroup } from './group.component';
6 |
7 | export type CompoundedCollapse = React.FunctionComponent
& {
8 | Header: typeof CollapseHeader;
9 | Body: typeof CollapseBody;
10 | Group: typeof CollapseGroup;
11 | };
12 |
13 | export interface CollapseProps extends DivProps {
14 | id?: string | number;
15 | active?: boolean;
16 | defaultActive?: boolean;
17 | onChange?: (value: any) => void;
18 | }
19 |
20 | export interface CollapseBodyProps extends DivProps {
21 | expanded?: boolean;
22 | }
23 |
24 | export interface CollapseGroupProps extends DivProps {
25 | onChange?: (value: any) => void;
26 | defaultActive?: string | number;
27 | children: React.ReactElement[] | React.ReactElement;
28 | }
29 |
30 | export interface CollapseHeaderProps extends ButtonProps {
31 | active?: boolean;
32 | activeSuffix?: React.ReactNode;
33 | activePrefix?: React.ReactNode;
34 | }
35 |
--------------------------------------------------------------------------------
/src/ui/collapse/group.component.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { useState } from 'react';
3 | import { useDefaultProps } from '../../utilities/useDefaultProps';
4 |
5 | import { Div } from '../div/div.component';
6 | import { CollapseGroupProps } from './collapse.type';
7 |
8 | const CollapseGroup: React.FunctionComponent = (
9 | incomingProps
10 | ) => {
11 | const props = useDefaultProps('CollapseGroup', incomingProps, {});
12 |
13 | const [activeId, setActiveId] = useState(props.defaultActive ?? null);
14 | const { children, onChange: onChangeProp, ...rest } = props;
15 |
16 | /**
17 | * checks if checked value is already in the state or not,
18 | * if it, remove it else add it
19 | *
20 | * @param value
21 | */
22 | const onChange = (optionId: any) => {
23 | setActiveId(optionId === activeId ? null : optionId);
24 |
25 | if (onChangeProp) {
26 | onChangeProp(optionId);
27 | }
28 | };
29 |
30 | /**
31 | * clones the children and add checked, onChange prop
32 | */
33 | const renderChildren = () => {
34 | return React.Children.map(children, (child: React.ReactElement) => {
35 | return React.cloneElement(child, {
36 | onChange,
37 | active: activeId === child.props.id,
38 | });
39 | });
40 | };
41 |
42 | return {renderChildren()}
;
43 | };
44 |
45 | export { CollapseGroup };
46 |
--------------------------------------------------------------------------------
/src/ui/div/div.spec.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render, screen } from '@testing-library/react-native';
3 |
4 | import { ThemeProvider } from '../../theme';
5 | import { Div } from './div.component';
6 | import { DivProps } from './div.type';
7 | import { Text } from '../text/text.component';
8 |
9 | describe('Div component', () => {
10 | const TestDiv: React.FC = (props) => (
11 |
12 |
13 |
14 | );
15 |
16 | it('should render component passed to children', () => {
17 | render(
18 |
19 | I love magnus ui
20 |
21 | );
22 |
23 | expect(screen.getByText('I love magnus ui')).toBeTruthy();
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/src/ui/div/div.style.tsx:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import { ThemeType } from '../../theme';
3 |
4 | import {
5 | createShadowStyles,
6 | createPositionStyle,
7 | createSpacingStyles,
8 | createBorderWidthStyles,
9 | createBorderColorStyles,
10 | createBorderRadiusStyles,
11 | getThemeColor,
12 | } from '../../theme/theme.service';
13 | import { DivProps } from './div.type';
14 |
15 | /**
16 | * computed style
17 | *
18 | * @param theme
19 | * @param props
20 | */
21 | export const getStyle = (theme: ThemeType, props: DivProps) => {
22 | const computedStyle: any = {};
23 |
24 | computedStyle.div = {
25 | flexDirection: props.row ? 'row' : props.flexDir,
26 | flexWrap: props.flexWrap,
27 | alignItems: props.alignItems,
28 | justifyContent: props.justifyContent,
29 | height: props.h,
30 | width: props.w,
31 | minWidth: props.minW,
32 | minHeight: props.minH,
33 | alignSelf: props.alignSelf,
34 | maxWidth: props.maxW,
35 | maxHeight: props.maxH,
36 | opacity: props.opacity,
37 | overflow: props.overflow,
38 | zIndex: props.zIndex,
39 | borderStyle: props.borderStyle,
40 | backgroundColor: getThemeColor(theme.colors, props.bg),
41 | flex: props.flex,
42 | ...createPositionStyle(props),
43 | ...createShadowStyles(props, theme),
44 | ...createBorderWidthStyles(props),
45 | ...createSpacingStyles(props, theme.spacing),
46 | ...createBorderColorStyles(props, theme.colors),
47 | ...createBorderRadiusStyles(props, theme.borderRadius),
48 | };
49 |
50 | computedStyle.image = {
51 | ...createBorderRadiusStyles(props, theme.borderRadius),
52 | };
53 |
54 | // merging custom style props to computed style
55 | if (props.style) {
56 | computedStyle.div = {
57 | ...computedStyle.div,
58 | // @ts-ignore
59 | ...props.style,
60 | };
61 | }
62 |
63 | return StyleSheet.create(computedStyle);
64 | };
65 |
--------------------------------------------------------------------------------
/src/ui/div/div.type.tsx:
--------------------------------------------------------------------------------
1 | import { ViewProps as RNViewProps } from 'react-native';
2 |
3 | import {
4 | BorderPropsType,
5 | SpacingPropsType,
6 | RoundedPropsType,
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 DivProps
19 | extends RNViewProps,
20 | BorderPropsType,
21 | SpacingPropsType,
22 | RoundedPropsType,
23 | ShadowPropsType,
24 | DimensionPropsType,
25 | BackgroundPropsType,
26 | FlexPropsType,
27 | PositionPropsType,
28 | ZIndexPropsType,
29 | OverflowPropsType,
30 | OpacityPropsType,
31 | VariantPropsType {}
32 |
--------------------------------------------------------------------------------
/src/ui/drawer/drawer.style.tsx:
--------------------------------------------------------------------------------
1 | import { StyleSheet, Dimensions } from 'react-native';
2 | import { ThemeType } from '../../theme';
3 |
4 | import {
5 | createBorderColorStyles,
6 | createBorderWidthStyles,
7 | createBorderRadiusStyles,
8 | getThemeColor,
9 | } from '../../theme/theme.service';
10 | import { DrawerProps } from './drawer.type';
11 |
12 | const SCREEN_WIDTH = Dimensions.get('window').width;
13 | const SCREEN_HEIGHT = Dimensions.get('window').height;
14 |
15 | /**
16 | * computed style
17 | *
18 | * @param theme
19 | * @param props
20 | */
21 | export const getStyle = (theme: ThemeType, props: DrawerProps) => {
22 | const computedStyle: any = {};
23 |
24 | computedStyle.drawer = {
25 | margin: 0,
26 | };
27 |
28 | computedStyle.container = {
29 | position: 'absolute',
30 | height: SCREEN_HEIGHT,
31 | // @ts-ignore
32 | width: SCREEN_WIDTH * (props.drawerPercentage / 100),
33 | zIndex: 0,
34 | margin: 0,
35 | backgroundColor: getThemeColor(theme.colors, props.bg),
36 | ...createBorderWidthStyles(props),
37 | ...createBorderColorStyles(props, theme.colors),
38 | ...createBorderRadiusStyles(props, theme.borderRadius),
39 | };
40 |
41 | computedStyle.safeView = {
42 | flex: 1,
43 | };
44 |
45 | if (props.direction === 'right') {
46 | computedStyle.container = {
47 | ...computedStyle.container,
48 | right: 0,
49 | };
50 | } else {
51 | computedStyle.container = {
52 | ...computedStyle.container,
53 | left: 0,
54 | };
55 | }
56 |
57 | return StyleSheet.create(computedStyle);
58 | };
59 |
--------------------------------------------------------------------------------
/src/ui/drawer/drawer.type.tsx:
--------------------------------------------------------------------------------
1 | import { ViewProps as RNViewProps } from 'react-native';
2 | import { ModalProps as RNModalProps } from '../modal/modal.type';
3 |
4 | import {
5 | BorderPropsType,
6 | RoundedPropsType,
7 | BackgroundPropsType,
8 | VariantPropsType,
9 | } from '../../types';
10 |
11 | export interface DrawerRef {
12 | close: () => void;
13 | open: () => void;
14 | }
15 |
16 | export interface DrawerProps
17 | extends Omit,
18 | RNViewProps,
19 | BorderPropsType,
20 | RoundedPropsType,
21 | Pick,
22 | VariantPropsType {
23 | direction?: 'left' | 'right';
24 | drawerPercentage?: number;
25 | animationTime?: number;
26 | }
27 |
--------------------------------------------------------------------------------
/src/ui/dropdown/dropdown.option.component.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { GestureResponderEvent as RNGestureResponderEvent } from 'react-native';
3 |
4 | import { DropdownOptionProps } from './dropdown.option.type';
5 | import { Button } from '../button/button.component';
6 | import { useDefaultProps } from '../../utilities/useDefaultProps';
7 |
8 | const DropdownOption: React.FunctionComponent = (
9 | incomingProps
10 | ) => {
11 | const props = useDefaultProps('DropdownOption', incomingProps, {
12 | onSelect: () => {},
13 | rounded: 0,
14 | bg: 'white',
15 | py: 'lg',
16 | px: '2xl',
17 | block: true,
18 | color: 'black',
19 | alignItems: 'center',
20 | justifyContent: 'flex-start',
21 | });
22 |
23 | const { children, value, onPress: onPressProp, onSelect, ...rest } = props;
24 |
25 | /**
26 | * on press select option
27 | *
28 | * @param e
29 | */
30 | const onPress = (event: RNGestureResponderEvent) => {
31 | if (onSelect) {
32 | onSelect(value);
33 | }
34 |
35 | if (onPressProp) {
36 | onPressProp(event);
37 | }
38 | };
39 |
40 | return (
41 |
42 | {children}
43 |
44 | );
45 | };
46 |
47 | // DropdownOption.defaultProps = {
48 | // onSelect: () => {},
49 | // rounded: 0,
50 | // bg: 'white',
51 | // p: 0,
52 | // color: 'black',
53 | // alignItems: 'flex-start',
54 | // justifyContent: 'flex-start',
55 | // };
56 |
57 | export { DropdownOption };
58 |
--------------------------------------------------------------------------------
/src/ui/dropdown/dropdown.option.type.tsx:
--------------------------------------------------------------------------------
1 | import { ButtonProps } from '../button/button.type';
2 |
3 | export interface DropdownOptionProps extends ButtonProps {
4 | value: any;
5 | onSelect?: (value: any) => void;
6 | }
7 |
--------------------------------------------------------------------------------
/src/ui/dropdown/dropdown.style.tsx:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import { ThemeType } from '../../theme';
3 |
4 | import {
5 | createSpacingStyles,
6 | createBorderWidthStyles,
7 | createBorderColorStyles,
8 | createBorderRadiusStyles,
9 | getThemeColor,
10 | } from '../../theme/theme.service';
11 | import { DropdownProps } from './dropdown.type';
12 |
13 | /**
14 | * computed style
15 | *
16 | * @param theme
17 | * @param props
18 | */
19 | export const getStyle = (theme: ThemeType, props: DropdownProps) => {
20 | const computedStyle: any = {};
21 |
22 | computedStyle.wrapper = {
23 | height: props.h,
24 | width: props.w,
25 | minHeight: props.minH,
26 | minWidth: props.minW,
27 | alignSelf: 'center',
28 | overflow: props.overflow,
29 | backgroundColor: getThemeColor(theme.colors, props.bg),
30 | ...createBorderWidthStyles(props),
31 | ...createBorderColorStyles(props, theme.colors),
32 | ...createBorderRadiusStyles(props, theme.borderRadius),
33 | };
34 |
35 | computedStyle.indicator = {
36 | alignSelf: 'center',
37 | marginVertical: 10,
38 | };
39 |
40 | computedStyle.container = {
41 | ...createSpacingStyles(props, theme.spacing),
42 | };
43 |
44 | computedStyle.options = {
45 | flexWrap: props.flexWrap,
46 | flexDirection: props.flexDir,
47 | alignItems: props.alignItems,
48 | justifyContent: props.justifyContent,
49 | };
50 |
51 | // merging style props to computed style
52 | if (props.style) {
53 | computedStyle.container = {
54 | ...computedStyle.container,
55 | // @ts-ignore
56 | ...props.style,
57 | };
58 | }
59 |
60 | return StyleSheet.create(computedStyle);
61 | };
62 |
--------------------------------------------------------------------------------
/src/ui/dropdown/dropdown.type.tsx:
--------------------------------------------------------------------------------
1 | import { ModalProps } from '../modal/modal.type';
2 |
3 | import { DropdownOption } from './dropdown.option.component';
4 | import {
5 | BorderPropsType,
6 | SpacingPropsType,
7 | RoundedPropsType,
8 | BackgroundPropsType,
9 | DimensionPropsType,
10 | FlexPropsType,
11 | OverflowPropsType,
12 | VariantPropsType,
13 | } from '../../types';
14 |
15 | export interface CompoundedDropdown
16 | extends React.ForwardRefExoticComponent<
17 | DropdownProps & React.RefAttributes
18 | > {
19 | Option: typeof DropdownOption;
20 | }
21 |
22 | export interface DropdownRef {
23 | open: () => void;
24 | close: () => void;
25 | }
26 |
27 | export interface DropdownProps
28 | extends ModalProps,
29 | BorderPropsType,
30 | SpacingPropsType,
31 | RoundedPropsType,
32 | DimensionPropsType,
33 | OverflowPropsType,
34 | Pick,
35 | Pick<
36 | FlexPropsType,
37 | 'justifyContent' | 'alignItems' | 'flexDir' | 'flexWrap'
38 | >,
39 | VariantPropsType {
40 | title?: string | React.ReactNode;
41 | showSwipeIndicator?: boolean;
42 | }
43 |
--------------------------------------------------------------------------------
/src/ui/fab/fab.style.tsx:
--------------------------------------------------------------------------------
1 | import { StyleSheet, Platform } from 'react-native';
2 | import { ThemeType } from '../../theme';
3 |
4 | import { getThemeColor } from '../../theme/theme.service';
5 | import { FabProps } from './fab.type';
6 |
7 | /**
8 | * computed style
9 | *
10 | * @param theme
11 | * @param props
12 | */
13 | export const getStyle = (theme: ThemeType, props: FabProps) => {
14 | const computedStyle: any = {};
15 |
16 | computedStyle.button = {
17 | bottom: 0,
18 | right: 0,
19 | overflow: Platform.OS === 'ios' ? 'visible' : 'hidden',
20 | zIndex: 2,
21 | alignItems: 'center',
22 | justifyContent: 'center',
23 | elevation: 5,
24 | position: props.position,
25 | };
26 |
27 | computedStyle.actions = {
28 | position: 'absolute',
29 | zIndex: 10,
30 | };
31 |
32 | if (props.shadow) {
33 | computedStyle.button = {
34 | ...computedStyle.button,
35 | ...(theme.shadow && theme.shadow[props.shadow]),
36 | shadowColor: getThemeColor(theme.colors, props.shadowColor),
37 | };
38 | }
39 |
40 | computedStyle.overlay = {
41 | position: 'absolute',
42 | bottom: 0,
43 | left: 0,
44 | right: 0,
45 | top: 0,
46 | elevation: 0,
47 | zIndex: 0,
48 | };
49 |
50 | return StyleSheet.create(computedStyle);
51 | };
52 |
--------------------------------------------------------------------------------
/src/ui/fab/fab.type.tsx:
--------------------------------------------------------------------------------
1 | import { PressableProps as RNButtonProps } from 'react-native';
2 | import {
3 | BackgroundPropsType,
4 | ButtonPropsType,
5 | DimensionPropsType,
6 | DisabledPropsType,
7 | FlexPropsType,
8 | LoadingPropsType,
9 | OverlayPropsType,
10 | PositionPropsType,
11 | TextPropsType,
12 | BorderPropsType,
13 | SpacingPropsType,
14 | RoundedPropsType,
15 | ShadowPropsType,
16 | VariantPropsType,
17 | } from '../../types';
18 |
19 | export interface FabProps
20 | extends Omit,
21 | BorderPropsType,
22 | SpacingPropsType,
23 | RoundedPropsType,
24 | ShadowPropsType,
25 | DimensionPropsType,
26 | FlexPropsType,
27 | LoadingPropsType,
28 | PositionPropsType,
29 | DisabledPropsType,
30 | OverlayPropsType,
31 | Pick,
32 | Pick,
33 | Pick,
34 | VariantPropsType {
35 | h?: number;
36 | center?: boolean;
37 | icon?: string | React.ReactNode;
38 | activeIcon?: string | React.ReactNode;
39 | showBackground?: boolean;
40 | openOnMount?: boolean;
41 | onClose?: () => void;
42 | onPressBackdrop?: () => void;
43 | animated?: boolean;
44 | onOpen?: () => void;
45 | useNativeDriver?: boolean;
46 | children: React.ReactElement | React.ReactElement[];
47 | }
48 |
--------------------------------------------------------------------------------
/src/ui/header/header.component.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { Text } from '../text/text.component';
3 | import { getStyle } from './header.style';
4 | import { useTheme } from '../../theme';
5 | import { HeaderProps } from './header.type';
6 | import { getSpecificProps } from '../../utilities';
7 | import { textProps } from '../../types';
8 | import { useDefaultProps } from '../../utilities/useDefaultProps';
9 | import { Div } from '../div/div.component';
10 |
11 | const Header: React.FunctionComponent = (incomingProps) => {
12 | const props = useDefaultProps('Header', incomingProps, {
13 | minH: 70,
14 | p: 'lg',
15 | bg: 'white',
16 | rounded: 'none',
17 | flexDir: 'row',
18 | shadow: 'sm',
19 | shadowColor: 'gray900',
20 | position: 'relative',
21 | bgMode: 'cover',
22 | pointerEvents: 'auto',
23 | borderStyle: 'solid',
24 | alignItems: 'center',
25 | alignment: 'left',
26 | fontWeight: 'bold',
27 | fontSize: 'lg',
28 | textTransform: 'uppercase',
29 | });
30 |
31 | const { children, prefix, suffix, ...rest } = props;
32 |
33 | const { theme } = useTheme();
34 | const computedStyle = getStyle(theme, props);
35 |
36 | /**
37 | * renders children based on type
38 | */
39 | const renderChildren = () => {
40 | if (typeof children === 'string') {
41 | return (
42 |
46 | {children}
47 |
48 | );
49 | }
50 |
51 | return children;
52 | };
53 |
54 | const getPrefix = () => {
55 | if (props.alignment === 'center') {
56 | return prefix;
57 | }
58 | return prefix ??
;
59 | };
60 |
61 | return (
62 |
63 |
{getPrefix()}
64 |
{renderChildren()}
65 |
{suffix}
66 |
67 | );
68 | };
69 |
70 | export { Header };
71 |
--------------------------------------------------------------------------------
/src/ui/header/header.style.tsx:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import { ThemeType } from '../../theme';
3 |
4 | import { HeaderProps } from './header.type';
5 |
6 | /**
7 | * computed styles
8 | *
9 | * @param theme
10 | * @param props
11 | */
12 | export const getStyle = (_theme: ThemeType, props: HeaderProps) => {
13 | const computedStyle: any = {};
14 |
15 | // merging style props to computed style
16 | if (props.style) {
17 | computedStyle.container = {
18 | ...computedStyle.container,
19 | // @ts-ignore
20 | ...props.style,
21 | };
22 | }
23 |
24 | computedStyle.center = {};
25 |
26 | if (props.suffix) {
27 | computedStyle.suffix = {
28 | zIndex: 1,
29 | flexDirection: 'row',
30 | alignItems: 'center',
31 | };
32 | }
33 |
34 | if (props.prefix) {
35 | computedStyle.prefix = {
36 | zIndex: 1,
37 | flexDirection: 'row',
38 | alignItems: 'center',
39 | };
40 | }
41 |
42 | if (props.alignment === 'center') {
43 | computedStyle.center = {
44 | ...computedStyle.center,
45 | justifyContent: 'center',
46 | alignItems: 'center',
47 | flex: 1,
48 | };
49 |
50 | computedStyle.container = {
51 | ...computedStyle.container,
52 | justifyContent: 'space-between',
53 | };
54 |
55 | if (props.suffix || props.prefix) {
56 | computedStyle.center = {
57 | ...computedStyle.center,
58 | ...StyleSheet.absoluteFillObject,
59 | };
60 |
61 | computedStyle.suffix = {
62 | ...computedStyle.suffix,
63 | flex: 1,
64 | justifyContent: 'flex-end',
65 | };
66 | }
67 | } else {
68 | computedStyle.center = {
69 | flex: 1,
70 | };
71 | }
72 |
73 | return StyleSheet.create(computedStyle);
74 | };
75 |
--------------------------------------------------------------------------------
/src/ui/header/header.type.tsx:
--------------------------------------------------------------------------------
1 | import { PrefixSuffixPropsType, TextPropsType } from '../../types';
2 | import { DivProps } from '../div/div.type';
3 |
4 | export interface HeaderProps
5 | extends DivProps,
6 | PrefixSuffixPropsType,
7 | TextPropsType {
8 | alignment?: 'center' | 'left';
9 | }
10 |
--------------------------------------------------------------------------------
/src/ui/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/ui/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),
41 | fontSize: getThemeProperty(theme.fontSize, props.fontSize),
42 | backgroundColor: getThemeColor(theme.colors, props.bg),
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/ui/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 | RoundedPropsType,
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 | RoundedPropsType,
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/ui/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 { ImageProps } from './image.type';
6 | import { useTheme } from '../../theme';
7 | import { useDefaultProps } from '../../utilities/useDefaultProps';
8 |
9 | const Image: React.FunctionComponent = (incomingProps) => {
10 | const props = useDefaultProps('Image', incomingProps, {});
11 |
12 | const {
13 | h,
14 | w,
15 | m,
16 | mt,
17 | mr,
18 | mb,
19 | ml,
20 | ms,
21 | p,
22 | pr,
23 | pt,
24 | pb,
25 | pl,
26 | minH,
27 | minW,
28 | maxH,
29 | maxW,
30 | style,
31 | rounded,
32 | roundedTop,
33 | roundedRight,
34 | roundedBottom,
35 | roundedLeft,
36 | borderColor,
37 | borderBottomColor,
38 | borderLeftColor,
39 | borderTopColor,
40 | borderRightColor,
41 | borderWidth,
42 | borderLeftWidth,
43 | borderRightWidth,
44 | borderBottomWidth,
45 | borderTopWidth,
46 | borderEndWidth,
47 | flex,
48 | shadow,
49 | shadowColor,
50 | position,
51 | top,
52 | right,
53 | bottom,
54 | left,
55 | zIndex,
56 | opacity,
57 | alignSelf,
58 | ...rest
59 | } = props;
60 | const { theme } = useTheme();
61 | const computedStyle = getStyle(theme, props);
62 |
63 | return ;
64 | };
65 |
66 | // Image.defaultProps = {};
67 |
68 | export { Image };
69 |
--------------------------------------------------------------------------------
/src/ui/image/image.style.tsx:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import { ThemeType } from '../../theme';
3 |
4 | import {
5 | createShadowStyles,
6 | createSpacingStyles,
7 | createPositionStyle,
8 | createBorderRadiusStyles,
9 | createBorderColorStyles,
10 | createBorderWidthStyles,
11 | getThemeColor,
12 | } from '../../theme/theme.service';
13 | import { ImageProps } from './image.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 | flex: props.flex,
26 | height: props.h,
27 | width: props.w,
28 | minHeight: props.minH,
29 | minWidth: props.minH,
30 | maxWidth: props.maxW,
31 | maxHeight: props.maxH,
32 | position: props.position,
33 | zIndex: props.zIndex,
34 | alignSelf: props.alignSelf,
35 | ...createPositionStyle(props),
36 | ...createBorderWidthStyles(props),
37 | ...createShadowStyles(props, theme),
38 | ...createSpacingStyles(props, theme.spacing),
39 | ...createBorderColorStyles(props, theme.colors),
40 | ...createBorderRadiusStyles(props, theme.borderRadius),
41 | backgroundColor: getThemeColor(theme.colors, props.bg),
42 | };
43 |
44 | // merging style props to computed style
45 | if (props.style) {
46 | computedStyle.image = {
47 | ...computedStyle.image,
48 | // @ts-ignore
49 | ...props.style,
50 | };
51 | }
52 |
53 | return StyleSheet.create(computedStyle);
54 | };
55 |
--------------------------------------------------------------------------------
/src/ui/image/image.type.tsx:
--------------------------------------------------------------------------------
1 | import { ImageProps as RNImageProps } from 'react-native';
2 | import {
3 | BackgroundPropsType,
4 | DimensionPropsType,
5 | FlexPropsType,
6 | OpacityPropsType,
7 | PositionPropsType,
8 | ZIndexPropsType,
9 | BorderPropsType,
10 | SpacingPropsType,
11 | RoundedPropsType,
12 | ShadowPropsType,
13 | VariantPropsType,
14 | } from '../../types';
15 |
16 | export interface ImageProps
17 | extends RNImageProps,
18 | BorderPropsType,
19 | SpacingPropsType,
20 | ShadowPropsType,
21 | RoundedPropsType,
22 | DimensionPropsType,
23 | PositionPropsType,
24 | OpacityPropsType,
25 | ZIndexPropsType,
26 | Pick,
27 | Pick,
28 | VariantPropsType {}
29 |
--------------------------------------------------------------------------------
/src/ui/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 | RoundedPropsType,
15 | ShadowPropsType,
16 | VariantPropsType,
17 | } from '../../types';
18 |
19 | export interface InputProps
20 | extends RNTextInputProps,
21 | BorderPropsType,
22 | SpacingPropsType,
23 | ShadowPropsType,
24 | RoundedPropsType,
25 | DimensionPropsType,
26 | LoadingPropsType,
27 | PrefixSuffixPropsType,
28 | ZIndexPropsType,
29 | OpacityPropsType,
30 | Pick,
31 | Pick,
32 | Omit,
33 | InputPropsType,
34 | VariantPropsType {}
35 |
--------------------------------------------------------------------------------
/src/ui/input/textarea.type.tsx:
--------------------------------------------------------------------------------
1 | import { InputProps } from './input.type';
2 |
3 | export interface TextareaProps extends InputProps {}
4 |
--------------------------------------------------------------------------------
/src/ui/mention/mention.style.tsx:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import { ThemeType } from '../../theme';
3 |
4 | import {
5 | createSpacingStyles,
6 | createBorderWidthStyles,
7 | createBorderColorStyles,
8 | createBorderRadiusStyles,
9 | createPositionStyle,
10 | getThemeColor,
11 | } from '../../theme/theme.service';
12 | import { MentionProps } from './mention.type';
13 |
14 | /**
15 | * computed style
16 | *
17 | * @param theme
18 | * @param props
19 | */
20 | export const getStyle = (theme: ThemeType, props: MentionProps) => {
21 | const computedStyle: any = {};
22 |
23 | computedStyle.list = {
24 | flex: 1,
25 | zIndex: 99,
26 | backgroundColor: getThemeColor(theme.colors, props.bg),
27 | ...createPositionStyle(props),
28 | ...createSpacingStyles(props, theme.spacing),
29 | ...createBorderWidthStyles(props),
30 | ...createBorderColorStyles(props, theme.colors),
31 | ...createBorderRadiusStyles(props, theme.borderRadius),
32 | };
33 |
34 | computedStyle.loading = {
35 | height: 60,
36 | marginTop: -60,
37 | zIndex: 99,
38 | alignItems: 'center',
39 | justifyContent: 'center',
40 | ...createSpacingStyles(props, theme.spacing),
41 | backgroundColor: getThemeColor(theme.colors, props.bg),
42 | ...createBorderWidthStyles(props),
43 | ...createBorderColorStyles(props, theme.colors),
44 | ...createBorderRadiusStyles(props, theme.borderRadius),
45 | flex: 1,
46 | };
47 |
48 | if (props.shadow) {
49 | computedStyle.list = {
50 | ...computedStyle.list,
51 | ...(theme.shadow && theme.shadow[props.shadow]),
52 | shadowColor: getThemeColor(theme.colors, props.shadowColor),
53 | };
54 | }
55 |
56 | // merging style props to computed style
57 | if (props.style) {
58 | computedStyle.container = {
59 | ...computedStyle.container,
60 | // @ts-ignore
61 | ...props.style,
62 | };
63 | }
64 |
65 | return StyleSheet.create(computedStyle);
66 | };
67 |
--------------------------------------------------------------------------------
/src/ui/mention/mention.type.tsx:
--------------------------------------------------------------------------------
1 | import { FlatListProps, ListRenderItemInfo } from 'react-native';
2 | import {
3 | BackgroundPropsType,
4 | LoadingPropsType,
5 | PositionPropsType,
6 | BorderPropsType,
7 | SpacingPropsType,
8 | RoundedPropsType,
9 | ShadowPropsType,
10 | VariantPropsType,
11 | } from '../../types';
12 |
13 | export interface MentionProps
14 | extends FlatListProps,
15 | BorderPropsType,
16 | SpacingPropsType,
17 | ShadowPropsType,
18 | RoundedPropsType,
19 | PositionPropsType,
20 | Pick,
21 | Pick,
22 | VariantPropsType {
23 | trigger?: any;
24 | h?: number;
25 | triggerLocation: 'new-word-only' | 'anywhere';
26 | onChangeText: (value: string) => void;
27 | triggerCallback: (lastKeyword: string) => void;
28 | children: React.ReactElement;
29 | onHide?: () => void;
30 | maxRow: number;
31 | renderItem: (rowData: ListRenderItemInfo) => any;
32 | }
33 |
--------------------------------------------------------------------------------
/src/ui/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/ui/overlay/overlay.style.tsx:
--------------------------------------------------------------------------------
1 | import color from 'color';
2 | import { StyleSheet } from 'react-native';
3 | import { ThemeType } from '../../theme';
4 |
5 | import {
6 | createFlexStyles,
7 | createSpacingStyles,
8 | createBorderRadiusStyles,
9 | getThemeColor,
10 | } from '../../theme/theme.service';
11 | import { OverlayProps } from './overlay.type';
12 |
13 | /**
14 | * computed style
15 | *
16 | * @param theme
17 | * @param props
18 | */
19 | export const getStyle = (theme: ThemeType, props: OverlayProps) => {
20 | const computedStyle: any = {};
21 |
22 | computedStyle.modal = {
23 | backgroundColor: color(getThemeColor(theme.colors, props.overlayColor))
24 | .alpha(props.overlayOpacity ?? 50)
25 | .rgb()
26 | .string(),
27 | flex: 1,
28 | alignItems: 'center',
29 | justifyContent: 'center',
30 | };
31 |
32 | computedStyle.container = {
33 | backgroundColor: getThemeColor(theme.colors, props.bg),
34 | ...createFlexStyles(props),
35 | ...createSpacingStyles(props, theme.spacing),
36 | ...createBorderRadiusStyles(props, theme.borderRadius),
37 | width: props.w,
38 | height: props.h,
39 | alignItems: props.alignItems,
40 | justifyContent: props.justifyContent,
41 | };
42 |
43 | // merging style props to computed style
44 | if (props.style) {
45 | computedStyle.container = {
46 | ...computedStyle.container,
47 | // @ts-ignore
48 | ...props.style,
49 | };
50 | }
51 |
52 | return StyleSheet.create(computedStyle);
53 | };
54 |
--------------------------------------------------------------------------------
/src/ui/overlay/overlay.type.tsx:
--------------------------------------------------------------------------------
1 | import { ModalProps as RNModalProps } from 'react-native';
2 | import {
3 | BackgroundPropsType,
4 | DimensionPropsType,
5 | FlexPropsType,
6 | OverlayPropsType,
7 | SpacingPropsType,
8 | RoundedPropsType,
9 | VariantPropsType,
10 | } from '../../types';
11 |
12 | export interface OverlayRef {
13 | close: () => void;
14 | open: () => void;
15 | }
16 |
17 | export interface OverlayProps
18 | extends RNModalProps,
19 | SpacingPropsType,
20 | RoundedPropsType,
21 | OverlayPropsType,
22 | Pick,
23 | Pick<
24 | FlexPropsType,
25 | 'flex' | 'justifyContent' | 'alignItems' | 'flexDir' | 'flexWrap'
26 | >,
27 | Pick,
28 | VariantPropsType {
29 | onBackdropPress?: () => void;
30 | }
31 |
--------------------------------------------------------------------------------
/src/ui/portal/consumer.component.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | import { IProvider } from './host.component';
4 |
5 | interface IConsumerProps {
6 | children: React.ReactNode;
7 | manager: IProvider | null;
8 | }
9 |
10 | export const Consumer = ({ children, manager }: IConsumerProps): null => {
11 | const key = React.useRef(undefined);
12 |
13 | const checkManager = (): void => {
14 | if (!manager) {
15 | throw new Error('No portal manager defined');
16 | }
17 | };
18 |
19 | const handleInit = (): void => {
20 | checkManager();
21 | key.current = manager?.mount(children);
22 | };
23 |
24 | React.useEffect(() => {
25 | checkManager();
26 | manager?.update(key.current, children);
27 | }, [children, manager]);
28 |
29 | React.useEffect(() => {
30 | handleInit();
31 |
32 | return (): void => {
33 | checkManager();
34 | manager?.unmount(key.current);
35 | };
36 | }, []);
37 |
38 | return null;
39 | };
40 |
--------------------------------------------------------------------------------
/src/ui/portal/hooks/useKey.ts:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | interface IUseKey {
4 | generateKey(): string;
5 | removeKey(key: string): void;
6 | }
7 |
8 | // Generates a random key
9 | const keyGenerator = (): string => {
10 | return `portalize_${Math.random().toString(36).substr(2, 16)}-${Math.random()
11 | .toString(36)
12 | .substr(2, 16)}-${Math.random().toString(36).substr(2, 16)}`;
13 | };
14 |
15 | // Custom hook that checks for uniqueness and retries if clashes
16 | export const useKey = (): IUseKey => {
17 | const usedKeys = React.useRef>([]);
18 |
19 | const generateKey = (): string => {
20 | let foundUniqueKey = false;
21 | let newKey = '';
22 | let tries = 0;
23 |
24 | while (!foundUniqueKey && tries < 3) {
25 | // limit number of tries to stop endless loop of pain
26 | tries++;
27 | newKey = keyGenerator();
28 |
29 | if (!usedKeys.current.includes(newKey)) {
30 | foundUniqueKey = true;
31 | }
32 | }
33 |
34 | // will only run if exited while loop without finding a unique key
35 | if (!foundUniqueKey) {
36 | newKey = `portalize_${Date.now()}_${Math.floor(Math.random() * 1000)}`; // fallback method
37 | }
38 |
39 | usedKeys.current.push(newKey);
40 | return newKey;
41 | };
42 |
43 | // Removes our key to make it 'available' again
44 | const removeKey = (key: string): void => {
45 | usedKeys.current = usedKeys.current.filter((k) => k !== key);
46 | };
47 |
48 | return { generateKey, removeKey };
49 | };
50 |
--------------------------------------------------------------------------------
/src/ui/portal/manager.component.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { View, StyleSheet } from 'react-native';
3 |
4 | export interface IManagerHandles {
5 | mount(key: string, children: React.ReactNode): void;
6 | update(key?: string, children?: React.ReactNode): void;
7 | unmount(key?: string): void;
8 | }
9 |
10 | export const Manager = React.forwardRef((_, ref): any => {
11 | const [portals, setPortals] = React.useState<
12 | { key: string; children: React.ReactNode }[]
13 | >([]);
14 |
15 | React.useImperativeHandle(
16 | ref,
17 | (): IManagerHandles => ({
18 | mount(key: string, children: React.ReactNode): void {
19 | setPortals((prev) => [...prev, { key, children }]);
20 | },
21 |
22 | update(key: string, children: React.ReactNode): void {
23 | setPortals((prev) =>
24 | prev.map((item) => {
25 | if (item.key === key) {
26 | return { ...item, children };
27 | }
28 |
29 | return item;
30 | })
31 | );
32 | },
33 |
34 | unmount(key: string): void {
35 | setPortals((prev) => prev.filter((item) => item.key !== key));
36 | },
37 | })
38 | );
39 |
40 | return portals.map(({ key, children }, index: number) => (
41 |
47 | {children}
48 |
49 | ));
50 | });
51 |
--------------------------------------------------------------------------------
/src/ui/portal/portal.component.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | import { Context } from './host.component';
4 | import { Consumer } from './consumer.component';
5 |
6 | interface IPortalProps {
7 | children: React.ReactNode;
8 | }
9 |
10 | export const Portal = ({ children }: IPortalProps): JSX.Element => (
11 |
12 | {(manager): JSX.Element => (
13 | {children}
14 | )}
15 |
16 | );
17 |
--------------------------------------------------------------------------------
/src/ui/radio/group.component.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { useState } from 'react';
3 |
4 | import { RadioGroupProps } from './radio.type';
5 | import { Div } from '../div/div.component';
6 | import { useDefaultProps } from '../../utilities/useDefaultProps';
7 |
8 | const RadioGroup: React.FunctionComponent = (
9 | incomingProps
10 | ) => {
11 | const props = useDefaultProps('RadioGroup', incomingProps, {});
12 |
13 | const [value, setValue] = useState(props.value ?? props.defaultValue ?? null);
14 | const {
15 | children,
16 | onChange: onChangeProp,
17 | value: propsValue,
18 | ...rest
19 | } = props;
20 |
21 | /**
22 | * checks if checked value is already in the state or not,
23 | * if it, remove it else add it
24 | *
25 | * @param value
26 | */
27 | const onChange = (optionValue: any) => {
28 | if (!('value' in props)) {
29 | setValue(optionValue);
30 | }
31 |
32 | if (onChangeProp) {
33 | onChangeProp(optionValue);
34 | }
35 | };
36 |
37 | /**
38 | * clones the children and add checked, onChange prop
39 | */
40 | const renderChildren = () => {
41 | return React.Children.map(children, (child: React.ReactElement) => {
42 | return React.cloneElement(child, {
43 | onChange,
44 | checked: value === child.props.value,
45 | });
46 | });
47 | };
48 |
49 | return {renderChildren()}
;
50 | };
51 |
52 | export { RadioGroup };
53 |
--------------------------------------------------------------------------------
/src/ui/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 | checked: any,
26 | disabled: any,
27 | activeColor: any,
28 | inactiveColor: any,
29 | theme: ThemeType
30 | ) => {
31 | switch (true) {
32 | case disabled:
33 | return getThemeColor(theme.colors, inactiveColor);
34 | case checked:
35 | return getThemeColor(theme.colors, activeColor);
36 | default:
37 | return getThemeColor(theme.colors, inactiveColor);
38 | }
39 | };
40 |
--------------------------------------------------------------------------------
/src/ui/scrolldiv/scrolldiv.type.ts:
--------------------------------------------------------------------------------
1 | import { ScrollViewProps as RNScrollViewProps } from 'react-native';
2 | import {
3 | BackgroundPropsType,
4 | DimensionPropsType,
5 | FlexPropsType,
6 | PositionPropsType,
7 | BorderPropsType,
8 | SpacingPropsType,
9 | RoundedPropsType,
10 | ShadowPropsType,
11 | VariantPropsType,
12 | } from '../../types';
13 |
14 | export interface ScrollDivProps
15 | extends RNScrollViewProps,
16 | BorderPropsType,
17 | SpacingPropsType,
18 | ShadowPropsType,
19 | RoundedPropsType,
20 | FlexPropsType,
21 | PositionPropsType,
22 | DimensionPropsType,
23 | BackgroundPropsType,
24 | VariantPropsType {}
25 |
--------------------------------------------------------------------------------
/src/ui/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 | RoundedPropsType,
16 | ShadowPropsType,
17 | VariantPropsType,
18 | } from '../../types';
19 |
20 | export interface SelectOptionProps
21 | extends RNButtonProps,
22 | BorderPropsType,
23 | SpacingPropsType,
24 | ShadowPropsType,
25 | RoundedPropsType,
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/ui/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),
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/ui/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 | RoundedPropsType,
10 | ShadowPropsType,
11 | VariantPropsType,
12 | } from '../../types';
13 | import { SelectOption } from './select.option.component';
14 |
15 | export interface CompoundedSelect
16 | extends React.ForwardRefExoticComponent<
17 | SelectProps & React.RefAttributes
18 | > {
19 | Option: typeof SelectOption;
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 | RoundedPropsType,
32 | ShadowPropsType,
33 | BackgroundPropsType,
34 | FlexPropsType,
35 | PositionPropsType,
36 | DimensionPropsType,
37 | VariantPropsType {
38 | title?: string | React.ReactNode;
39 | message?: string | React.ReactNode;
40 |
41 | showScrollIndicator?: boolean;
42 |
43 | multiple?: boolean;
44 | value: any;
45 | footer?: React.ReactElement[] | React.ReactElement;
46 | onSelect: (value: any) => void;
47 | data: any[];
48 | renderItem: (item: any, index: number) => React.ReactElement;
49 | keyExtractor?: (item: any, index: number) => string;
50 | isVisible?: boolean;
51 |
52 | searchableProps?: '*' | string[];
53 | renderNoResultsView?: (searchTerm: string) => React.ReactElement;
54 | renderSubmitButton?: () => React.ReactElement;
55 | renderSearchInput?: (props: { clearText: () => void }) => React.ReactElement;
56 | }
57 |
--------------------------------------------------------------------------------
/src/ui/skeleton/skeleton.component.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import * as Animatable from 'react-native-animatable';
3 | import { useDefaultProps } from '../../utilities/useDefaultProps';
4 |
5 | import { Div } from '../div/div.component';
6 | import { SkeletonProps, CompundedSkeleton } from './skeleton.type';
7 |
8 | const Skeleton: CompundedSkeleton = (incomingProps) => {
9 | const props = useDefaultProps('Skeleton', incomingProps, {
10 | bg: 'gray400',
11 | h: 15,
12 | w: '100%',
13 | rounded: 'lg',
14 | duration: 1000,
15 | });
16 |
17 | const { duration, ...rest } = props;
18 |
19 | Animatable.initializeRegistryWithDefinitions({
20 | fade: {
21 | 0: {
22 | opacity: 1,
23 | },
24 | 0.5: {
25 | opacity: 0.3,
26 | },
27 | 1: {
28 | opacity: 1,
29 | },
30 | },
31 | });
32 |
33 | return (
34 |
40 |
41 |
42 | );
43 | };
44 |
45 | export const Circle: React.FunctionComponent = (
46 | incomingProps
47 | ) => {
48 | const props = useDefaultProps('SkeletonCircle', incomingProps, {
49 | bg: 'gray400',
50 | h: 15,
51 | w: 15,
52 | rounded: 'circle',
53 | });
54 |
55 | return ;
56 | };
57 |
58 | Skeleton.defaultProps = {
59 | bg: 'gray400',
60 | h: 15,
61 | w: '100%',
62 | rounded: 'lg',
63 | duration: 1000,
64 | };
65 |
66 | Circle.defaultProps = {
67 | bg: 'gray400',
68 | h: 15,
69 | w: 15,
70 | rounded: 'circle',
71 | };
72 |
73 | Skeleton.Box = Skeleton;
74 | Skeleton.Circle = Circle;
75 |
76 | export { Skeleton };
77 |
--------------------------------------------------------------------------------
/src/ui/skeleton/skeleton.type.tsx:
--------------------------------------------------------------------------------
1 | import { DivProps } from '../div/div.type';
2 | import { Skeleton, Circle } from './skeleton.component';
3 |
4 | export type CompundedSkeleton = React.FunctionComponent
& {
5 | Box: typeof Skeleton;
6 | Circle: typeof Circle;
7 | };
8 |
9 | export interface SkeletonProps extends DivProps {
10 | duration?: number;
11 | }
12 |
--------------------------------------------------------------------------------
/src/ui/snackbar/snackbar.style.tsx:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native';
2 | import { ThemeType } from '../../theme';
3 |
4 | import {
5 | createShadowStyles,
6 | createSpacingStyles,
7 | createBorderColorStyles,
8 | createBorderWidthStyles,
9 | createBorderRadiusStyles,
10 | getThemeColor,
11 | } from '../../theme/theme.service';
12 | import { SnackbarProps } from './snackbar.type';
13 |
14 | /**
15 | * computed style
16 | *
17 | * @param theme
18 | * @param props
19 | */
20 | export const getStyle = (theme: ThemeType, props: SnackbarProps) => {
21 | const computedStyle: any = {};
22 |
23 | computedStyle.wrapper = {
24 | width: '100%',
25 | };
26 |
27 | computedStyle.text = {
28 | flex: 1,
29 | };
30 |
31 | computedStyle.prefix = {
32 | marginRight: 8,
33 | };
34 |
35 | computedStyle.suffix = {
36 | marginLeft: 8,
37 | };
38 |
39 | computedStyle.container = {
40 | flexDirection: props.flexDir,
41 | justifyContent: props.justifyContent,
42 | alignItems: props.justifyContent,
43 | alignSelf: props.alignSelf,
44 | width: props.w,
45 | height: props.h,
46 | minWidth: props.minW,
47 | minHeight: props.minH,
48 | maxWidth: props.maxW,
49 | maxHeight: props.maxH,
50 | opacity: props.opacity,
51 | ...createShadowStyles(props, theme),
52 | ...createBorderWidthStyles(props),
53 | ...createSpacingStyles(props, theme.spacing),
54 | ...createBorderColorStyles(props, theme.colors),
55 | ...createBorderRadiusStyles(props, theme.borderRadius),
56 | backgroundColor: getThemeColor(theme.colors, props.bg),
57 | };
58 |
59 | return StyleSheet.create(computedStyle);
60 | };
61 |
--------------------------------------------------------------------------------
/src/ui/snackbar/snackbar.type.tsx:
--------------------------------------------------------------------------------
1 | import { ReactNode } from 'react';
2 | import { StyleProp, ViewStyle } from 'react-native';
3 | import {
4 | BackgroundPropsType,
5 | DimensionPropsType,
6 | FlexPropsType,
7 | OpacityPropsType,
8 | PrefixSuffixPropsType,
9 | TextPropsType,
10 | BorderPropsType,
11 | SpacingPropsType,
12 | RoundedPropsType,
13 | ShadowPropsType,
14 | VariantPropsType,
15 | } from '../../types';
16 |
17 | export interface SnackbarRef {
18 | show: (message: string | JSX.Element, config?: SnackbarProps) => void;
19 | hide: (id: string) => void;
20 | update: (
21 | id: string,
22 | message: string | JSX.Element,
23 | config?: SnackbarProps
24 | ) => void;
25 | }
26 |
27 | export interface SnackbarProps
28 | extends BorderPropsType,
29 | SpacingPropsType,
30 | ShadowPropsType,
31 | RoundedPropsType,
32 | PrefixSuffixPropsType,
33 | DimensionPropsType,
34 | OpacityPropsType,
35 | FlexPropsType,
36 | Pick,
37 | Pick,
38 | VariantPropsType {
39 | id?: string;
40 | duration?: number;
41 | onClose?: () => void;
42 | style?: StyleProp;
43 | useNativeDriver?: boolean;
44 | children?: ReactNode;
45 | }
46 |
47 | export interface SnackbarContainerProps {
48 | placement: 'top' | 'bottom';
49 | offset?: number;
50 | }
51 |
52 | export interface SnackbarState {
53 | toasts: Array;
54 | }
55 |
--------------------------------------------------------------------------------
/src/ui/statusbar/statusbar.component.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {
3 | StatusBar as RNStatusBar,
4 | StatusBarProps as RNStatusBarProps,
5 | } from 'react-native';
6 | import { useTheme } from '../../theme';
7 |
8 | import { getThemeColor } from '../../theme/theme.service';
9 | import { VariantPropsType } from '../../types';
10 | import { useDefaultProps } from '../../utilities/useDefaultProps';
11 |
12 | interface StatusBarComponent extends React.FC {
13 | currentHeight?: number;
14 | }
15 |
16 | const StatusBar: StatusBarComponent = (
17 | incomingProps
18 | ) => {
19 | const props = useDefaultProps('Statusbar', incomingProps, {
20 | animated: true,
21 | });
22 |
23 | const { backgroundColor } = props;
24 | const { theme } = useTheme();
25 |
26 | return (
27 |
35 | );
36 | };
37 |
38 | StatusBar.currentHeight = RNStatusBar.currentHeight;
39 |
40 | // StatusBar.defaultProps = {
41 | // animated: true,
42 | // };
43 |
44 | export { StatusBar };
45 |
--------------------------------------------------------------------------------
/src/ui/tag/tag.component.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | import { TagProps } from './tag.type';
4 | import { useDefaultProps } from '../../utilities/useDefaultProps';
5 | import { Button } from '../button/button.component';
6 |
7 | const Tag: React.FunctionComponent = (incomingProps) => {
8 | const props = useDefaultProps('Tag', incomingProps, {
9 | px: 'lg',
10 | py: 'sm',
11 | bg: 'gray400',
12 | color: 'black',
13 | fontSize: 'lg',
14 | textAlign: 'auto',
15 | textTransform: 'none',
16 | rounded: 'md',
17 | borderWidth: 0,
18 | borderColor: 'transparent',
19 | onPress: () => {},
20 | });
21 |
22 | const { underlayColor, ...rest } = props;
23 |
24 | return ;
25 | };
26 |
27 | export { Tag };
28 |
--------------------------------------------------------------------------------
/src/ui/tag/tag.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 { TagProps } from './tag.type';
12 |
13 | /**
14 | * computed style
15 | *
16 | * @param theme
17 | * @param props
18 | */
19 | export const getStyle = (theme: ThemeType, props: TagProps) => {
20 | const computedStyle: any = {};
21 |
22 | computedStyle.div = {
23 | borderColor: getThemeColor(theme.colors, props.borderColor),
24 | borderWidth: props.borderWidth,
25 | justifyContent: 'center',
26 | alignItems: 'center',
27 | flexDirection: 'row',
28 | alignSelf: 'flex-start',
29 | backgroundColor: getThemeColor(theme.colors, props.bg),
30 | ...createBorderWidthStyles(props),
31 | ...createSpacingStyles(props, theme.spacing),
32 | ...createBorderColorStyles(props, theme.colors),
33 | ...createBorderRadiusStyles(props, theme.borderRadius),
34 | };
35 |
36 | computedStyle.prefix = {
37 | marginRight: 4,
38 | };
39 |
40 | computedStyle.suffix = {
41 | marginLeft: 4,
42 | };
43 |
44 | if (props.h) {
45 | computedStyle.div = {
46 | ...computedStyle.div,
47 | height: props.h,
48 | };
49 | }
50 |
51 | if (props.w) {
52 | computedStyle.div = {
53 | ...computedStyle.div,
54 | width: props.w,
55 | };
56 | }
57 |
58 | if (props.minH) {
59 | computedStyle.div = {
60 | ...computedStyle.div,
61 | minHeight: props.minH,
62 | };
63 | }
64 |
65 | if (props.minW) {
66 | computedStyle.div = {
67 | ...computedStyle.div,
68 | minWidth: props.minW,
69 | };
70 | }
71 |
72 | // merging style props to computed style
73 | if (props.style) {
74 | computedStyle.div = {
75 | ...computedStyle.div,
76 | // @ts-ignore
77 | ...props.style,
78 | };
79 | }
80 |
81 | return StyleSheet.create(computedStyle);
82 | };
83 |
--------------------------------------------------------------------------------
/src/ui/tag/tag.type.tsx:
--------------------------------------------------------------------------------
1 | import { ButtonProps } from '../button/button.type';
2 |
3 | export interface TagProps extends ButtonProps {}
4 |
--------------------------------------------------------------------------------
/src/ui/text/text.component.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { Text as RNText } from 'react-native';
3 |
4 | import { TextProps } from './text.type';
5 | import { getStyle } from './text.style';
6 | import { useTheme } from '../../theme';
7 | import { useDefaultProps } from '../../utilities/useDefaultProps';
8 |
9 | const Text: React.FunctionComponent = (incomingProps) => {
10 | const props = useDefaultProps('Text', incomingProps, {
11 | color: 'gray900',
12 | textAlign: 'auto',
13 | textTransform: 'none',
14 | fontSize: 'md',
15 | overflow: 'hidden',
16 | textAlignVertical: 'center',
17 | });
18 |
19 | const {
20 | w,
21 | h,
22 | bg,
23 | m,
24 | mt,
25 | mr,
26 | mb,
27 | ml,
28 | ms,
29 | p,
30 | pr,
31 | pt,
32 | pb,
33 | pl,
34 | flex,
35 | minH,
36 | minW,
37 | color,
38 | fontSize,
39 | children,
40 | textAlign,
41 | fontWeight,
42 | lineHeight,
43 | letterSpacing,
44 | textTransform,
45 | textDecorColor,
46 | textDecorStyle,
47 | fontStyle,
48 | textDecorLine,
49 | textAlignVertical,
50 | overflow,
51 | opacity,
52 | zIndex,
53 | style,
54 | ...rest
55 | } = props;
56 | const { theme } = useTheme();
57 | const computedStyle = getStyle(theme, props);
58 |
59 | return (
60 |
61 | {children}
62 |
63 | );
64 | };
65 |
66 | // Text.defaultProps = {
67 | // color: 'gray900',
68 | // textAlign: 'auto',
69 | // textTransform: 'none',
70 | // fontSize: 'md',
71 | // overflow: 'hidden',
72 | // };
73 |
74 | export { Text };
75 |
--------------------------------------------------------------------------------
/src/ui/text/text.type.ts:
--------------------------------------------------------------------------------
1 | import { TextProps as RNTextProps } from 'react-native';
2 | import {
3 | BackgroundPropsType,
4 | DimensionPropsType,
5 | FlexPropsType,
6 | OpacityPropsType,
7 | OverflowPropsType,
8 | TextPropsType,
9 | ZIndexPropsType,
10 | BorderPropsType,
11 | SpacingPropsType,
12 | RoundedPropsType,
13 | VariantPropsType,
14 | } from '../../types';
15 |
16 | export interface TextProps
17 | extends RNTextProps,
18 | SpacingPropsType,
19 | RoundedPropsType,
20 | BorderPropsType,
21 | TextPropsType,
22 | DimensionPropsType,
23 | OverflowPropsType,
24 | OpacityPropsType,
25 | ZIndexPropsType,
26 | Pick,
27 | Pick,
28 | VariantPropsType {}
29 |
--------------------------------------------------------------------------------
/src/ui/toggle/toggle.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 { ToggleProps } from './toggle.type';
9 |
10 | /**
11 | * computed style
12 | *
13 | * @param theme
14 | * @param props
15 | */
16 | export const getStyle = (theme: ThemeType, props: ToggleProps) => {
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.h - 6,
31 | // @ts-ignore
32 | width: props.h - 6,
33 | // @ts-ignore
34 | borderRadius: props.h - 6,
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/ui/toggle/toggle.type.tsx:
--------------------------------------------------------------------------------
1 | import { TouchableOpacityProps as RNTouchableOpacityProps } from 'react-native';
2 |
3 | import {
4 | BackgroundPropsType,
5 | DimensionPropsType,
6 | DisabledPropsType,
7 | BorderPropsType,
8 | SpacingPropsType,
9 | RoundedPropsType,
10 | VariantPropsType,
11 | } from '../../types';
12 |
13 | export interface ToggleProps
14 | extends SpacingPropsType,
15 | RoundedPropsType,
16 | BorderPropsType,
17 | DisabledPropsType,
18 | Pick,
19 | Pick,
20 | Pick,
21 | DisabledPropsType,
22 | VariantPropsType {
23 | testID?: string;
24 | on?: boolean;
25 | onPress: () => void;
26 | activeBg?: string;
27 | circleBg?: string;
28 | activeCircleBg?: string;
29 | duration?: number;
30 | }
31 |
--------------------------------------------------------------------------------
/src/ui/tooltip/tooltip.type.tsx:
--------------------------------------------------------------------------------
1 | import { ViewProps as RNViewProps } from 'react-native';
2 | import {
3 | BackgroundPropsType,
4 | DimensionPropsType,
5 | TextPropsType,
6 | ZIndexPropsType,
7 | SpacingPropsType,
8 | RoundedPropsType,
9 | ShadowPropsType,
10 | OpacityPropsType,
11 | VariantPropsType,
12 | } from '../../types';
13 |
14 | export interface TooltipRef {
15 | hide: () => void;
16 | show: () => void;
17 | }
18 |
19 | export interface TooltipProps
20 | extends RNViewProps,
21 | SpacingPropsType,
22 | ShadowPropsType,
23 | RoundedPropsType,
24 | TextPropsType,
25 | DimensionPropsType,
26 | OpacityPropsType,
27 | ZIndexPropsType,
28 | Pick,
29 | VariantPropsType {
30 | animationDuration?: number;
31 | text: string | React.ReactNode;
32 | useNativeDriver?: boolean;
33 | }
34 |
35 | export interface TriangleProps extends RNViewProps {
36 | invert: boolean;
37 | }
38 |
--------------------------------------------------------------------------------
/src/ui/tooltip/triangle.component.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { View as RNView, StyleSheet } from 'react-native';
3 | import { useDefaultProps } from '../../utilities/useDefaultProps';
4 | import { TriangleProps } from './tooltip.type';
5 |
6 | const Triangle: React.FunctionComponent = (incomingProps) => {
7 | const props = useDefaultProps(null, incomingProps, {
8 | invert: true,
9 | });
10 |
11 | const { style, invert } = props;
12 | let computedStyle = style;
13 |
14 | if (invert) {
15 | computedStyle = StyleSheet.flatten([
16 | style,
17 | {
18 | transform: [{ rotate: '180deg' }],
19 | },
20 | ]);
21 | }
22 |
23 | return ;
24 | };
25 |
26 | export { Triangle };
27 |
--------------------------------------------------------------------------------
/src/utilities/useDefaultProps.ts:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { ThemeType, useTheme } from '../theme';
3 | import { DefaultProps, VariantPropsType } from '../types';
4 |
5 | export const useDefaultProps = (
6 | componentName: keyof NonNullable | null,
7 | props: Props & VariantPropsType,
8 | defaultProps: DefaultProps
9 | ) => {
10 | const { theme } = useTheme();
11 |
12 | const finalProps = React.useMemo(() => {
13 | if (!componentName) {
14 | return {
15 | ...defaultProps,
16 | ...props,
17 | };
18 | }
19 |
20 | let propsFromTheme = {
21 | ...(theme.components?.[componentName] ?? {}),
22 | ...(props.variant &&
23 | (theme.components?.[componentName]?.variants?.[props.variant] ?? {})),
24 | };
25 |
26 | delete propsFromTheme.variants;
27 |
28 | const mergedProps = {
29 | ...defaultProps,
30 | ...propsFromTheme,
31 | ...props,
32 | };
33 |
34 | return mergedProps;
35 | }, [componentName, defaultProps, props, theme.components]);
36 |
37 | return finalProps as Props & Required;
38 | };
39 |
--------------------------------------------------------------------------------
/src/utilities/withDefaultProps.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { ThemeContext, ThemeType } from '../theme';
3 | import { DefaultProps, VariantPropsType } from '../types';
4 |
5 | export function withDefaultProps<
6 | Props extends object,
7 | Defaults extends DefaultProps = {}
8 | >(
9 | WrappedComponent: React.ComponentClass,
10 | componentName: keyof NonNullable,
11 | defaultProps: Defaults
12 | ) {
13 | type Variant = Props & VariantPropsType;
14 | return class extends React.PureComponent {
15 | static contextType = ThemeContext;
16 | // using `declare` requires babel plugin which doesn't seem to work
17 | // class related components & HOC's should be refactored anyway
18 | // @ts-ignore
19 | context!: React.ContextType;
20 |
21 | render() {
22 | const theme = this.context.theme;
23 |
24 | if (!componentName) {
25 | return ;
26 | }
27 |
28 | let propsFromTheme = {
29 | ...(theme.components?.[componentName] ?? {}),
30 | ...(this.props.variant &&
31 | //@ts-ignore
32 | (theme.components?.[componentName]?.variants?.[this.props.variant] ??
33 | {})),
34 | };
35 |
36 | delete propsFromTheme.variants;
37 |
38 | const mergedProps = {
39 | ...defaultProps,
40 | ...propsFromTheme,
41 | ...this.props,
42 | };
43 |
44 | return ;
45 | }
46 | };
47 | }
48 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": ".",
4 | "paths": {
5 | "react-native-magnus": ["./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"]
26 | },
27 | "exclude": ["./**/*.spec.ts", "./**/*.spec.tsx"]
28 | }
29 |
--------------------------------------------------------------------------------