Skip to content

Commit

Permalink
feat(checkbox): add checkbox component
Browse files Browse the repository at this point in the history
  • Loading branch information
Artur Bien committed Nov 29, 2020
1 parent e916559 commit aad32ce
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 62 deletions.
56 changes: 32 additions & 24 deletions example/src/examples/CheckboxExample.tsx
Original file line number Diff line number Diff line change
@@ -1,39 +1,47 @@
import React, { useState } from 'react';
import { StyleSheet } from 'react-native';
import { Checkbox, Cutout, original } from 'react95-native';
import Container from '../util/Container';
import { Checkbox, Panel, Fieldset } from 'react95-native';

const CheckboxExample = () => {
const [isChecked, setIsChecked] = useState(false);
const [isIndeterminate, setIsIndeterminate] = useState(true);

return (
<Container>
<Container.Section title='Basic usage'>
<Cutout style={styles.container}>
<Checkbox
status={isChecked ? 'checked' : 'unchecked'}
onPress={() => setIsChecked(oldIsChecked => !oldIsChecked)}
label='Potato'
/>
</Cutout>
</Container.Section>
<Container.Section title='Disabled'>
<Cutout style={styles.container}>
<Checkbox
status='checked'
onPress={() => console.warn('pressed')}
label='Disabled'
disabled
/>
</Cutout>
</Container.Section>
</Container>
<Panel style={styles.container}>
<Fieldset label='Default'>
<Checkbox
status={isChecked ? 'checked' : 'unchecked'}
onPress={() => setIsChecked(prevState => !prevState)}
label='Potato'
/>
<Checkbox
status='checked'
onPress={() => console.warn('pressed')}
label='Disabled'
disabled
/>
</Fieldset>
<Fieldset label='Indeterminate'>
<Checkbox
status={isIndeterminate ? 'indeterminate' : 'unchecked'}
onPress={() => setIsIndeterminate(prevState => !prevState)}
label='Potato'
/>
<Checkbox
status='indeterminate'
onPress={() => console.warn('pressed')}
label='Disabled'
disabled
/>
</Fieldset>
</Panel>
);
};

const styles = StyleSheet.create({
container: {
backgroundColor: original.material,
flex: 1,
padding: 16,
},
});

Expand Down
2 changes: 1 addition & 1 deletion example/src/examples/FieldsetExample.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const DividerExample = () => {
<Fieldset label='Name:'>
<Text style={[{ fontSize: 16 }]}>Some text here</Text>
</Fieldset>
<Fieldset label=''>
<Fieldset>
<Text style={[{ fontSize: 16 }]}>No label here</Text>
</Fieldset>
</Panel>
Expand Down
128 changes: 94 additions & 34 deletions src/Checkbox/Checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,76 +2,136 @@ import React from 'react';
import {
StyleProp,
StyleSheet,
TouchableOpacity,
TouchableHighlight,
ImageBackground,
View,
ViewStyle,
} from 'react-native';

import { Border } from '../common/styleElements';
import { original as theme } from '../common/themes';
import { border } from '../common/styles';

import { Text } from '..';

const checkboxSize = 20;

type Props = {
status: 'checked' | 'unchecked' | 'indeterminate';
disabled?: boolean;
label?: string;
onPress?: () => void;
status: 'checked' | 'unchecked' | 'indeterminate';
style?: StyleProp<ViewStyle>;
disabled?: boolean;
};

const Checkbox = ({
status,
disabled = false,
label = '',
onPress = () => {},
disabled = false,
status,
style = {},
}: Props) => {
const [isPressed, setIsPressed] = React.useState(false);

const renderBox = () => {
if (status === 'checked') {
return <Text>-</Text>;
return (
<ImageBackground
// border to compensate for Border
style={[{ width: '100%', height: '100%', borderWidth: 4 }]}
imageStyle={{
resizeMode: 'contain',
flex: 1,
}}
source={{
uri: disabled
? 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAAR0lEQVQoU2NkIAIw4lPT0tryv6a6hhGnIpACkAFwRTAdMFNhCjAUwQTQFYDEwdYhS8BMA1kDY8MZ2EzAUAQzEdkErIpwBQcA7RckCvjAHfcAAAAASUVORK5CYII='
: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAAQ0lEQVQoU42Q0Q4AIARFj///6BqNSat4sXFcF6ER8mEGIC9IAY2AbCKpOnBAVgA2wIuac8MFQ/m6Ih9UjVdvy3njTUwR1AkKqm4yNwAAAABJRU5ErkJggg==',
}}
/>
);
}
if (status === 'indeterminate') {
return (
<ImageBackground
style={[{ width: '100%', height: '100%' }]}
imageStyle={{
resizeMode: 'repeat',
}}
source={{
uri: disabled
? 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAJElEQVQoU2NsaW35z4AEaqprGJH5jHRQgGwfiI1uJYqDaKMAAHKtGjlbjgHwAAAAAElFTkSuQmCC'
: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAJElEQVQoU2NkYGD4z4AKGJG5IA4dFKA5AdVKFAdBVaK4iXIFAEiuCAWq9MdHAAAAAElFTkSuQmCC',
}}
/>
);
}

return <Text> </Text>;
};

return (
<View style={styles.container}>
<TouchableOpacity
style={[
styles.base,
{ backgroundColor: disabled ? theme.material : theme.canvas },
style,
]}
onPress={onPress}
activeOpacity={1}
disabled={disabled}
accessibilityTraits={disabled ? ['button', 'disabled'] : 'button'}
accessibilityComponentType='button'
accessibilityRole='checkbox'
accessibilityState={{ disabled, checked: status === 'checked' }}
>
<>
<Border variant='cutout' />
<TouchableHighlight
style={[styles.wrapper, style]}
onPress={onPress}
activeOpacity={1}
disabled={disabled}
onHideUnderlay={() => setIsPressed(false)}
onShowUnderlay={() => setIsPressed(true)}
// TODO: check if those accessibility properties are correct
accessibilityTraits={disabled ? ['button', 'disabled'] : 'button'}
accessibilityComponentType='button'
accessibilityRole='checkbox'
accessibilityState={{ disabled, checked: status === 'checked' }}
underlayColor='none'
>
<View style={[styles.content]} pointerEvents='none'>
<View
style={[
styles.checkbox,
{ backgroundColor: disabled ? theme.material : theme.canvas },
]}
>
{renderBox()}
</>
</TouchableOpacity>
{Boolean(label) && <Text>{label}</Text>}
</View>
<Border variant='cutout' />
</View>
{Boolean(label) && (
<View
style={[
!disabled && isPressed
? border.focusOutline
: { borderWidth: 2, borderColor: 'transparent' },
]}
>
<Text disabled={disabled} style={[styles.label]}>
{label}
</Text>
</View>
)}
</View>
</TouchableHighlight>
);
};

const styles = StyleSheet.create({
container: {
wrapper: {
width: 'auto',
alignSelf: 'flex-start',
padding: 4,
backgroundColor: theme.material,
},
content: {
flexDirection: 'row',
alignItems: 'center',
width: 'auto',
},
base: {
width: 36,
height: 36,
alignItems: 'center',
justifyContent: 'space-around',
marginRight: 12,
checkbox: {
width: checkboxSize,
height: checkboxSize,
marginRight: 8,
},
label: {
fontSize: 16,
},
});

Expand Down
4 changes: 2 additions & 2 deletions src/Fieldset/Fieldset.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Border } from '../common/styleElements';
export const testId = 'fieldset';

type Props = {
label: React.ReactNode;
label?: React.ReactNode;
children: React.ReactNode;
style?: Object;
};
Expand All @@ -32,7 +32,7 @@ const Fieldset = ({ children, label, style = {} }: Props) => {
const styles = StyleSheet.create({
wrapper: {
position: 'relative',
marginTop: 8,
marginVertical: 12,
padding: 12,
},
label: {
Expand Down
5 changes: 4 additions & 1 deletion src/Panel/Panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ type Props = {

const Panel = ({ children, variant = 'default', style = {} }: Props) => {
return (
<View style={[styles.container, style]} testID={testId}>
<View
style={[styles.container, { padding: variant === 'well' ? 2 : 4 }, style]}
testID={testId}
>
<Border variant={variant} />
{children}
</View>
Expand Down

0 comments on commit aad32ce

Please sign in to comment.