From a08f2e0cc17a3c404bce5532241b26a7d5c1023a Mon Sep 17 00:00:00 2001 From: Artur Bien Date: Sun, 29 Nov 2020 22:26:02 +0100 Subject: [PATCH] feat(radio): add radio component --- example/src/examples/CheckboxExample.tsx | 2 +- example/src/examples/RadioExample.tsx | 52 +++++++ example/src/examples/index.tsx | 2 + src/Checkbox/Checkbox.tsx | 124 ++-------------- src/Radio/Radio.tsx | 32 +++++ src/Radio/index.ts | 1 + src/SwitchBase/SwitchBase.tsx | 173 +++++++++++++++++++++++ src/SwitchBase/index.ts | 1 + src/common/styleElements.tsx | 12 +- src/index.ts | 1 + 10 files changed, 283 insertions(+), 117 deletions(-) create mode 100644 example/src/examples/RadioExample.tsx create mode 100644 src/Radio/Radio.tsx create mode 100644 src/Radio/index.ts create mode 100644 src/SwitchBase/SwitchBase.tsx create mode 100644 src/SwitchBase/index.ts diff --git a/example/src/examples/CheckboxExample.tsx b/example/src/examples/CheckboxExample.tsx index 4f667f7..8372568 100644 --- a/example/src/examples/CheckboxExample.tsx +++ b/example/src/examples/CheckboxExample.tsx @@ -3,7 +3,7 @@ import { StyleSheet } from 'react-native'; import { Checkbox, Panel, Fieldset } from 'react95-native'; const CheckboxExample = () => { - const [isChecked, setIsChecked] = useState(false); + const [isChecked, setIsChecked] = useState(true); const [isIndeterminate, setIsIndeterminate] = useState(true); return ( diff --git a/example/src/examples/RadioExample.tsx b/example/src/examples/RadioExample.tsx new file mode 100644 index 0000000..d0691c1 --- /dev/null +++ b/example/src/examples/RadioExample.tsx @@ -0,0 +1,52 @@ +import React, { useState } from 'react'; +import { StyleSheet } from 'react-native'; +import { Radio, Panel, Fieldset } from 'react95-native'; + +const CheckboxExample = () => { + const [value, setValue] = useState('Apple'); + + return ( + +
+ setValue('Apple')} + label='Apple' + /> + setValue('Orange')} + label='Orange' + /> + setValue('Watermelon')} + label='Watermelon' + /> +
+
+ console.warn('pressed')} + label='Apple' + disabled + /> + console.warn('pressed')} + label='Pear' + disabled + /> +
+
+ ); +}; + +const styles = StyleSheet.create({ + container: { + flex: 1, + padding: 16, + }, +}); + +export default CheckboxExample; diff --git a/example/src/examples/index.tsx b/example/src/examples/index.tsx index f57ead5..3ed4146 100644 --- a/example/src/examples/index.tsx +++ b/example/src/examples/index.tsx @@ -6,6 +6,7 @@ import CutoutExample from './CutoutExample'; import TextExample from './TextExample'; import DividerExample from './DividerExample'; import CheckboxExample from './CheckboxExample'; +import RadioExample from './RadioExample'; import WindowExample from './WindowExample'; import FieldsetExample from './FieldsetExample'; import MenuExample from './MenuExample'; @@ -20,6 +21,7 @@ export default [ { name: 'TextExample', component: TextExample, title: 'Text' }, { name: 'DividerExample', component: DividerExample, title: 'Divider' }, { name: 'CheckboxExample', component: CheckboxExample, title: 'Checkbox' }, + { name: 'RadioExample', component: RadioExample, title: 'Radio' }, { name: 'WindowExample', component: WindowExample, title: 'Window' }, { name: 'FieldsetExample', component: FieldsetExample, title: 'Fieldset' }, { name: 'MenuExample', component: MenuExample, title: 'Menu' }, diff --git a/src/Checkbox/Checkbox.tsx b/src/Checkbox/Checkbox.tsx index e822d55..0dc3645 100644 --- a/src/Checkbox/Checkbox.tsx +++ b/src/Checkbox/Checkbox.tsx @@ -1,20 +1,6 @@ import React from 'react'; -import { - StyleProp, - StyleSheet, - 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; +import { StyleProp, ViewStyle } from 'react-native'; +import SwitchBase from '../SwitchBase'; type Props = { disabled?: boolean; @@ -31,108 +17,16 @@ const Checkbox = ({ status, style = {}, }: Props) => { - const [isPressed, setIsPressed] = React.useState(false); - - const renderBox = () => { - if (status === 'checked') { - return ( - - ); - } - if (status === 'indeterminate') { - return ( - - ); - } - - return ; - }; - return ( - 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' - > - - - {renderBox()} - - - {Boolean(label) && ( - - - {label} - - - )} - - + label={label} + onPress={onPress} + status={status} + style={style} + /> ); }; -const styles = StyleSheet.create({ - wrapper: { - width: 'auto', - alignSelf: 'flex-start', - padding: 4, - backgroundColor: theme.material, - }, - content: { - flexDirection: 'row', - alignItems: 'center', - width: 'auto', - }, - checkbox: { - width: checkboxSize, - height: checkboxSize, - marginRight: 8, - }, - label: { - fontSize: 16, - }, -}); - export default Checkbox; diff --git a/src/Radio/Radio.tsx b/src/Radio/Radio.tsx new file mode 100644 index 0000000..0a983c2 --- /dev/null +++ b/src/Radio/Radio.tsx @@ -0,0 +1,32 @@ +import React from 'react'; +import { StyleProp, ViewStyle } from 'react-native'; +import SwitchBase from '../SwitchBase'; + +type Props = { + disabled?: boolean; + label?: string; + onPress?: () => void; + status: 'checked' | 'unchecked'; + style?: StyleProp; +}; + +const Radio = ({ + disabled = false, + label = '', + onPress = () => {}, + status, + style = {}, +}: Props) => { + return ( + + ); +}; + +export default Radio; diff --git a/src/Radio/index.ts b/src/Radio/index.ts new file mode 100644 index 0000000..61c9567 --- /dev/null +++ b/src/Radio/index.ts @@ -0,0 +1 @@ +export { default } from './Radio'; diff --git a/src/SwitchBase/SwitchBase.tsx b/src/SwitchBase/SwitchBase.tsx new file mode 100644 index 0000000..44e5f6b --- /dev/null +++ b/src/SwitchBase/SwitchBase.tsx @@ -0,0 +1,173 @@ +import React from 'react'; +import { + StyleProp, + StyleSheet, + 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 switchSize = 20; + +type Props = { + disabled?: boolean; + label?: string; + onPress?: () => void; + status: 'checked' | 'unchecked' | 'indeterminate'; + component: 'radio' | 'checkbox'; + style?: StyleProp; +}; + +const symbols = { + checkbox: { + default: + 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAAQ0lEQVQoU42Q0Q4AIARFj///6BqNSat4sXFcF6ER8mEGIC9IAY2AbCKpOnBAVgA2wIuac8MFQ/m6Ih9UjVdvy3njTUwR1AkKqm4yNwAAAABJRU5ErkJggg==', + disabled: + 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAAR0lEQVQoU2NkIAIw4lPT0tryv6a6hhGnIpACkAFwRTAdMFNhCjAUwQTQFYDEwdYhS8BMA1kDY8MZ2EzAUAQzEdkErIpwBQcA7RckCvjAHfcAAAAASUVORK5CYII=', + }, + radio: { + default: + 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAKElEQVQoU2NkIAAYSVXwH6oBrhHZBJgkzFCwHEkKQBrwWoHVvQR9AQAfmgQJp08TYAAAAABJRU5ErkJggg==', + disabled: + 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAALUlEQVQoU2NkIAAYSVLQ0tryH6ShproGrhHOgEnCTIQpIl4BSCdeK3A5lqAvAEBkEAkDjL/SAAAAAElFTkSuQmCC', + }, + indeterminate: { + default: + 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAJElEQVQoU2NkYGD4z4AKGJG5IA4dFKA5AdVKFAdBVaK4iXIFAEiuCAWq9MdHAAAAAElFTkSuQmCC', + disabled: + 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAJElEQVQoU2NsaW35z4AEaqprGJH5jHRQgGwfiI1uJYqDaKMAAHKtGjlbjgHwAAAAAElFTkSuQmCC', + }, +}; + +const SwitchBase = ({ + disabled = false, + label = '', + onPress = () => {}, + component, + status, + style = {}, +}: Props) => { + const [isPressed, setIsPressed] = React.useState(false); + const isRadio = component === 'radio'; + const borderRadius = isRadio ? switchSize / 2 : 0; + + const renderBox = () => { + if (status === 'checked') { + const symbol = symbols[component][disabled ? 'disabled' : 'default']; + + return ( + + ); + } + if (status === 'indeterminate') { + const symbol = symbols[status][disabled ? 'disabled' : 'default']; + + return ( + + ); + } + + return ; + }; + + return ( + setIsPressed(false)} + onShowUnderlay={() => setIsPressed(true)} + // TODO: check if those accessibility properties are correct + accessibilityTraits={disabled ? ['button', 'disabled'] : 'button'} + accessibilityComponentType='button' + accessibilityRole={component} + accessibilityState={{ disabled, checked: status === 'checked' }} + underlayColor='none' + > + + + {renderBox()} + + + {Boolean(label) && ( + + + {label} + + + )} + + + ); +}; + +const styles = StyleSheet.create({ + wrapper: { + width: 'auto', + alignSelf: 'flex-start', + padding: 4, + backgroundColor: theme.material, + }, + content: { + flexDirection: 'row', + alignItems: 'center', + width: 'auto', + }, + switchSymbol: { + width: switchSize, + height: switchSize, + marginRight: 8, + }, + label: { + fontSize: 16, + }, +}); + +export default SwitchBase; diff --git a/src/SwitchBase/index.ts b/src/SwitchBase/index.ts new file mode 100644 index 0000000..dfd6f37 --- /dev/null +++ b/src/SwitchBase/index.ts @@ -0,0 +1 @@ +export { default } from './SwitchBase'; diff --git a/src/common/styleElements.tsx b/src/common/styleElements.tsx index 4f19c1e..d27216f 100644 --- a/src/common/styleElements.tsx +++ b/src/common/styleElements.tsx @@ -10,12 +10,16 @@ type BorderProps = { invert?: boolean; variant?: 'default' | 'well' | 'outside' | 'cutout'; style?: object; + size?: number; + round?: boolean; }; export const Border = ({ invert = false, variant = 'default', style = {}, + size, + round, }: BorderProps) => { const wrapper: StyleProp = []; let outer; @@ -34,7 +38,13 @@ export const Border = ({ inner = [border.cutoutInner]; } - const sharedStyles = [borderStyles.position]; + const sharedStyles = [ + borderStyles.position, + { + borderRadius: round && size ? size / 2 : 0, + }, + ]; + return (