Skip to content

Commit fcfefae

Browse files
committed
feat(formfield): expose formfield
1 parent 9bf4c9d commit fcfefae

16 files changed

Lines changed: 1424 additions & 1966 deletions

src/components/Checkbox/Checkbox.mdx

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ menu: Components
55

66
import { Toggle } from 'react-powerplug';
77
import { Playground, Props } from 'docz';
8+
import { Text } from 'react-native';
89
import { Checkbox } from '.';
10+
import { FormField } from '../Form';
911

1012
# Checkbox
1113

@@ -14,20 +16,22 @@ import { Checkbox } from '.';
1416
<Playground>
1517
<Toggle initial={false}>
1618
{({ on, toggle }) => (
17-
<Checkbox
18-
shape="square" // or "circle"
19-
isChecked={on}
20-
isDisabled={false}
21-
isInteractive={true}
22-
onChange={toggle}
23-
size="medium"
24-
getStyles={(props, theme) => ({
25-
checkboxStyle: {},
26-
checkboxFocusBackgroundColor: '',
27-
})}
28-
labelPosition="right" // or left
29-
label="Label"
30-
/>
19+
<FormField label="Checkbox" labelPosition="right">
20+
<Checkbox
21+
shape="square" // or "circle"
22+
isChecked={on}
23+
isDisabled={false}
24+
isInteractive={true}
25+
onChange={toggle}
26+
size="medium"
27+
getStyles={(props, theme) => ({
28+
touchableStyle: {},
29+
checkboxStyle: {},
30+
iconColor: 'white',
31+
checkboxFocusBackgroundColor: '',
32+
})}
33+
/>
34+
</FormField>
3135
)}
3236
</Toggle>
3337
</Playground>

src/components/Checkbox/Checkbox.styles.ts

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,19 @@
1-
import { TextStyle, ViewStyle } from 'react-native';
1+
import { ViewStyle } from 'react-native';
22

33
import { ControlSize, Theme } from '../../theme/ThemeInterface';
4-
import { CheckboxLabelPosition, CheckboxShape } from './Checkbox';
4+
import { CheckboxShape } from './Checkbox';
55

66
export interface CheckboxStylesProps {
77
isChecked: boolean;
88
isDisabled: boolean;
99
shape: CheckboxShape;
10-
labelPosition: CheckboxLabelPosition;
11-
hasLabel: boolean;
1210
checkColor: string;
1311
size: ControlSize;
1412
}
1513

1614
export interface CheckboxStyles {
1715
touchableStyle: ViewStyle;
18-
outerWrapperStyle: ViewStyle;
1916
checkboxStyle: ViewStyle;
20-
textStyle: TextStyle;
2117
iconColor: string;
2218
checkboxFocusBackgroundColor: string;
2319
}
@@ -28,7 +24,7 @@ export type GetCheckboxStyles = (
2824
) => CheckboxStyles;
2925

3026
export const getCheckboxStyles: GetCheckboxStyles = (
31-
{ isChecked, isDisabled, shape, hasLabel, labelPosition, checkColor, size },
27+
{ isChecked, isDisabled, shape, checkColor, size },
3228
theme,
3329
) => {
3430
const sizeValue = theme.controlHeights[size] - 16;
@@ -46,11 +42,6 @@ export const getCheckboxStyles: GetCheckboxStyles = (
4642
height: sizeValue,
4743
justifyContent: 'center',
4844
width: sizeValue,
49-
...(hasLabel
50-
? labelPosition === 'right'
51-
? { marginRight: 8 }
52-
: { marginLeft: 8 }
53-
: {}),
5445
...(isChecked
5546
? {
5647
backgroundColor: theme.colors.background.primaryDefault,
@@ -74,11 +65,6 @@ export const getCheckboxStyles: GetCheckboxStyles = (
7465
},
7566
iconColor: checkColor || theme.colors.text.white,
7667

77-
outerWrapperStyle: {
78-
alignItems: 'center',
79-
flexDirection: 'row',
80-
},
81-
textStyle: {},
8268
touchableStyle: {},
8369
};
8470
};

src/components/Checkbox/Checkbox.tsx

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,13 @@ import { DeepPartial } from 'ts-essentials';
1010
import { ControlSize, useTheme } from '../../theme';
1111
import { mergeStyles, ReplaceReturnType } from '../../utils/mergeStyles';
1212
import { Icon } from '../Icon';
13-
import { Text } from '../Typography';
1413
import {
1514
CheckboxStyles,
1615
GetCheckboxStyles,
1716
getCheckboxStyles,
1817
} from './Checkbox.styles';
1918

2019
export type CheckboxShape = 'circle' | 'square';
21-
export type CheckboxLabelPosition = 'left' | 'right';
2220

2321
export interface CheckboxProps extends AccessibilityProps {
2422
isChecked?: boolean;
@@ -31,9 +29,7 @@ export interface CheckboxProps extends AccessibilityProps {
3129
getStyles?: ReplaceReturnType<GetCheckboxStyles, DeepPartial<CheckboxStyles>>;
3230
testID?: string;
3331
checkColor?: string;
34-
label?: string;
3532
size?: ControlSize;
36-
labelPosition?: 'left' | 'right';
3733
}
3834

3935
export const Checkbox = (props: CheckboxProps) => {
@@ -43,9 +39,7 @@ export const Checkbox = (props: CheckboxProps) => {
4339
isInteractive = true,
4440
onChange = () => null,
4541
shape = 'square',
46-
labelPosition = 'right',
4742
size = 'medium',
48-
label,
4943
checkColor,
5044
getStyles,
5145
testID,
@@ -56,18 +50,14 @@ export const Checkbox = (props: CheckboxProps) => {
5650

5751
const {
5852
touchableStyle,
59-
outerWrapperStyle,
6053
checkboxStyle,
61-
textStyle,
6254
iconColor,
6355
checkboxFocusBackgroundColor,
6456
} = mergeStyles(getCheckboxStyles, getStyles)(
6557
{
6658
checkColor,
67-
hasLabel: !!label,
6859
isChecked,
6960
isDisabled,
70-
labelPosition,
7161
shape,
7262
size,
7363
},
@@ -90,22 +80,8 @@ export const Checkbox = (props: CheckboxProps) => {
9080
testID={testID}
9181
{...accessibilityProps}
9282
>
93-
<View style={outerWrapperStyle}>
94-
{labelPosition === 'left' && (
95-
<Text size={size} getStyles={() => ({ textStyle })}>
96-
{label}
97-
</Text>
98-
)}
99-
100-
<View style={checkboxStyle}>
101-
{isChecked ? <Icon name="check" size={20} color={iconColor} /> : null}
102-
</View>
103-
104-
{labelPosition === 'right' && (
105-
<Text size={size} getStyles={() => ({ textStyle })}>
106-
{label}
107-
</Text>
108-
)}
83+
<View style={checkboxStyle}>
84+
{isChecked ? <Icon name="check" size={20} color={iconColor} /> : null}
10985
</View>
11086
</TouchableHighlight>
11187
);

src/components/Form/FormField.mdx

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
---
2+
name: FormField
3+
menu: Components
4+
---
5+
6+
import { Text } from 'react-native';
7+
import { Toggle } from 'react-powerplug';
8+
9+
import { FormField } from '.';
10+
import { Playground, Props } from 'docz';
11+
import { TextInput } from '../Inputs';
12+
13+
# FormField
14+
15+
### Usage
16+
17+
<Playground>
18+
<FormField
19+
labelPosition="top"
20+
label="Email"
21+
description="Description for the field"
22+
error="Error message"
23+
getStyles={(props, theme) => ({
24+
containerStyles: {},
25+
descriptionTextStyle: {},
26+
errorTextStyle: {},
27+
errorWrapperStyle: {},
28+
labelTextStyle: {},
29+
labelWrapperStyle: {},
30+
wrapperStyle: {},
31+
})}
32+
>
33+
<TextInput />
34+
</FormField>
35+
</Playground>
36+
37+
### Props
38+
39+
<Props of={FormField} />
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { TextStyle, ViewStyle } from 'react-native';
2+
3+
import { Theme } from '../../theme/ThemeInterface';
4+
import { FormFieldLabelPosition } from './FormField';
5+
6+
export interface FormFieldStylesProps {
7+
labelPosition?: FormFieldLabelPosition;
8+
}
9+
10+
export interface FormFieldStyles {
11+
containerStyles: ViewStyle;
12+
descriptionTextStyle: TextStyle;
13+
errorTextStyle: TextStyle;
14+
errorWrapperStyle: ViewStyle;
15+
labelTextStyle: TextStyle;
16+
labelWrapperStyle: ViewStyle;
17+
wrapperStyle: ViewStyle;
18+
}
19+
20+
export type GetFormFieldStyles = (
21+
FormFieldStylesProps: FormFieldStylesProps,
22+
theme: Theme,
23+
) => FormFieldStyles;
24+
25+
export const getFormFieldStyles: GetFormFieldStyles = (
26+
{ labelPosition },
27+
theme,
28+
) => {
29+
let labelWrapperStyle: ViewStyle = {};
30+
let wrapperStyle: ViewStyle = {};
31+
32+
switch (labelPosition) {
33+
case 'left':
34+
labelWrapperStyle = { paddingRight: 8 };
35+
wrapperStyle = { flexDirection: 'row', alignItems: 'center' };
36+
break;
37+
case 'right':
38+
labelWrapperStyle = { paddingLeft: 8 };
39+
wrapperStyle = { flexDirection: 'row', alignItems: 'center' };
40+
break;
41+
default:
42+
labelWrapperStyle = { paddingBottom: 4 };
43+
wrapperStyle = { paddingBottom: 4 };
44+
break;
45+
}
46+
47+
return {
48+
containerStyles: {},
49+
descriptionTextStyle: { paddingBottom: 4 },
50+
errorTextStyle: {},
51+
errorWrapperStyle: {},
52+
labelTextStyle: {},
53+
labelWrapperStyle,
54+
wrapperStyle,
55+
};
56+
};

src/components/Form/FormField.tsx

Lines changed: 72 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,88 @@
11
import * as React from 'react';
2+
import { View } from 'react-native';
3+
import { DeepPartial } from 'ts-essentials';
24

3-
import { Box } from '../Box';
5+
import { useTheme } from '../../theme';
6+
import { mergeStyles, ReplaceReturnType } from '../../utils/mergeStyles';
47
import { Label, Text } from '../Typography';
8+
import {
9+
FormFieldStyles,
10+
GetFormFieldStyles,
11+
getFormFieldStyles,
12+
} from './FormField.styles';
13+
14+
export type FormFieldLabelPosition = 'top' | 'left' | 'right';
515

616
export interface FormFieldProps {
7-
error?: string | null;
8-
label?: string | null;
9-
description?: string | null;
17+
error?: string;
18+
label?: string;
19+
labelPosition?: FormFieldLabelPosition;
20+
description?: string;
1021
children?: React.ReactNode;
22+
getStyles?: ReplaceReturnType<
23+
GetFormFieldStyles,
24+
DeepPartial<FormFieldStyles>
25+
>;
1126
}
1227

1328
export const FormField = (props: FormFieldProps) => {
14-
const { label, error, children, description, ...passThroughProps } = props;
29+
const {
30+
label,
31+
error,
32+
children,
33+
description,
34+
labelPosition = 'top',
35+
getStyles,
36+
} = props;
37+
const theme = useTheme();
38+
39+
const {
40+
containerStyles,
41+
descriptionTextStyle,
42+
errorTextStyle,
43+
errorWrapperStyle,
44+
labelTextStyle,
45+
labelWrapperStyle,
46+
wrapperStyle,
47+
} = mergeStyles(getFormFieldStyles, getStyles)(
48+
{
49+
labelPosition,
50+
},
51+
theme,
52+
);
53+
54+
const labelContent = (
55+
<View style={labelWrapperStyle}>
56+
<Label getStyles={() => ({ textStyle: labelTextStyle })}>{label}</Label>
57+
</View>
58+
);
1559

1660
return (
17-
<Box>
18-
{label && (
19-
<Box marginBottom={4}>
20-
<Label>{label}</Label>
21-
</Box>
61+
<View style={containerStyles}>
62+
{label && labelPosition === 'top' && labelContent}
63+
<View style={wrapperStyle}>
64+
{label && labelPosition === 'left' && labelContent}
65+
{children}
66+
{label && labelPosition === 'right' && labelContent}
67+
</View>
68+
{description && (
69+
<Text
70+
color="muted"
71+
getStyles={() => ({ textStyle: descriptionTextStyle })}
72+
>
73+
{description}
74+
</Text>
2275
)}
23-
<Box marginBottom={4}>
24-
{/*
25-
// @ts-ignore: TODO: Find right way to type this */}
26-
{React.cloneElement(children, passThroughProps)}
27-
</Box>
2876
{error && (
29-
<Box marginBottom={4}>
30-
<Text color="danger">{error}</Text>
31-
</Box>
77+
<View style={errorWrapperStyle}>
78+
<Text
79+
color="danger"
80+
getStyles={() => ({ textStyle: errorTextStyle })}
81+
>
82+
{error}
83+
</Text>
84+
</View>
3285
)}
33-
{description && <Text>{description}</Text>}
34-
</Box>
86+
</View>
3587
);
3688
};

0 commit comments

Comments
 (0)