Skip to content

Commit

Permalink
feat(selectbox): add SelectBox component
Browse files Browse the repository at this point in the history
  • Loading branch information
Artur Bien committed Dec 5, 2020
1 parent aaa331a commit 38094ba
Show file tree
Hide file tree
Showing 7 changed files with 214 additions and 71 deletions.
32 changes: 32 additions & 0 deletions example/src/examples/SelectBoxExample.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React, { useState } from 'react';
import { Panel, SelectBox, Fieldset } from 'react95-native';

const options = ['apple', 'orange', 'banana', 'pear', 'watermelon'].map(o => ({
label: o,
value: o,
}));

const SelectBoxExample = () => {
const [value, setValue] = useState(options[0].value);
return (
<Panel style={{ flex: 1, padding: 20 }}>
<Fieldset label='Default:' style={[{ padding: 20 }]}>
<SelectBox
options={options}
value={value}
onChange={newValue => setValue(newValue)}
/>
</Fieldset>
<Fieldset label='Custom size:' style={[{ padding: 20 }]}>
<SelectBox
options={options}
value={value}
onChange={newValue => setValue(newValue)}
style={[{ width: 200, height: 120 }]}
/>
</Fieldset>
</Panel>
);
};

export default SelectBoxExample;
2 changes: 2 additions & 0 deletions example/src/examples/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import FieldsetExample from './FieldsetExample';
import MenuExample from './MenuExample';
import ProgressExample from './ProgressExample';
import SelectExample from './SelectExample';
import SelectBoxExample from './SelectBoxExample';
import DesktopExample from './DesktopExample';
import TabsExample from './TabsExample';

Expand All @@ -30,6 +31,7 @@ export default [
{ name: 'MenuExample', component: MenuExample, title: 'Menu' },
{ name: 'ProgressExample', component: ProgressExample, title: 'Progress' },
{ name: 'SelectExample', component: SelectExample, title: 'Select' },
{ name: 'SelectBoxExample', component: SelectBoxExample, title: 'SelectBox' },
{ name: 'DesktopExample', component: DesktopExample, title: 'Desktop' },
{ name: 'TabsExample', component: TabsExample, title: 'Tabs' },
].sort((a, b) => {
Expand Down
84 changes: 15 additions & 69 deletions src/Select/Select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,59 +6,12 @@ import {
TouchableHighlight,
ImageBackground,
} from 'react-native';

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

type Option = {
value: any;
label: React.ReactNode;
};

type SelectItemProps = {
option: Option;
onPress: () => void;
isSelected: boolean;
};

const SelectItem = ({ option, onPress, isSelected }: SelectItemProps) => {
const [isPressed, setIsPressed] = useState(false);

return (
<TouchableHighlight
onPress={() => onPress(option)}
onHideUnderlay={() => setIsPressed(false)}
onShowUnderlay={() => setIsPressed(true)}
accessibilityRole='menuitem'
underlayColor='none'
>
<View
style={[
styles.center,
styles.optionWrapper,
{
backgroundColor:
isPressed || isSelected ? theme.hoverBackground : theme.canvas,
},
]}
>
<Text
style={[
styles.optionText,
{
color:
isPressed || isSelected
? theme.canvasTextInvert
: theme.canvasText,
},
]}
>
{option.label}
</Text>
</View>
</TouchableHighlight>
);
};
import getSelectOptions, { Option } from './SelectBase';

const dropdownSymbol = {
default:
Expand Down Expand Up @@ -86,13 +39,17 @@ const Select = ({
const [isOpen, setIsOpen] = useState(false);
const [isPressed, setIsPressed] = useState(false);

const selectedIndex = options.findIndex(option => option.value === value);

function handleOptionSelect(option: Option) {
onChange(option.value);
setIsOpen(false);
}
const [selectedOptions, selectOptions] = getSelectOptions({
options,
values: [value],
onChange: handleOptionSelect,
});

const selectedOption = selectedOptions[0];
// TODO: close dropdown when user touches outside of component
// TODO: native prop to use native select

Expand All @@ -115,7 +72,7 @@ const Select = ({
<View style={[styles.flex]}>
<View
style={[
styles.value,
styles.selectValue,
{ backgroundColor: disabled ? theme.material : theme.canvas },
]}
>
Expand Down Expand Up @@ -147,7 +104,7 @@ const Select = ({
},
]}
>
{options[selectedIndex].label}
{selectedOption.label}
</Text>
</View>
</View>
Expand Down Expand Up @@ -178,14 +135,9 @@ const Select = ({

{isOpen && (
<View style={[styles.options]}>
{options.map((option, index) => (
<SelectItem
key={option.value}
option={option}
isSelected={index === selectedIndex}
onPress={handleOptionSelect}
/>
))}
{/* <ScrollView> */}
{selectOptions}
{/* </ScrollView> */}
</View>
)}
</View>
Expand All @@ -212,7 +164,7 @@ const styles = StyleSheet.create({
alignItems: 'center',
height: '100%',
},
value: {
selectValue: {
flexGrow: 1,
flex: 1,
height: '100%',
Expand Down Expand Up @@ -244,12 +196,6 @@ const styles = StyleSheet.create({
borderWidth: 2,
borderColor: theme.borderDarkest,
padding: 2,
},
optionWrapper: {
height: selectHeight - 4,
},
optionText: {
fontSize: 16,
paddingLeft: 6,
display: 'flex',
},
});
102 changes: 102 additions & 0 deletions src/Select/SelectBase.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import React, { useState } from 'react';
import { StyleSheet, View, Text, TouchableHighlight } from 'react-native';
import { original as theme } from '../common/themes';
import { blockSizes } from '../common/styles';

export type Option = {
value: any;
label: React.ReactNode;
};

type SelectItemProps = {
option: Option;
onPress: () => void;
isSelected: boolean;
};

const SelectItem = ({ option, onPress, isSelected }: SelectItemProps) => {
const [isPressed, setIsPressed] = useState(false);

return (
<TouchableHighlight
onPress={() => onPress(option)}
onHideUnderlay={() => setIsPressed(false)}
onShowUnderlay={() => setIsPressed(true)}
accessibilityRole='menuitem'
underlayColor='none'
// delay to prevent item highlighting on scroll
delayPressIn={70}
>
<View
style={[
styles.center,
styles.optionWrapper,
{
backgroundColor:
isPressed || isSelected ? theme.hoverBackground : theme.canvas,
},
]}
>
<Text
style={[
styles.optionText,
{
color:
isPressed || isSelected
? theme.canvasTextInvert
: theme.canvasText,
},
]}
>
{option.label}
</Text>
</View>
</TouchableHighlight>
);
};

const selectHeight = blockSizes.md + 2;

const styles = StyleSheet.create({
center: {
flexGrow: 1,
flex: 1,
height: '100%',
justifyContent: 'center',
},
optionWrapper: {
height: selectHeight - 4,
},
optionText: {
fontSize: 16,
paddingLeft: 6,
},
});

type SelectOptionsProps = {
options: Array<Option>;
values: [any];
disabled?: boolean;
// TODO: what to put below?
onChange: () => void;
};

export default function getSelectOptions({
options,
values,
onChange,
}: SelectOptionsProps) {
const selectedOptions = options.filter(option =>
values.includes(option.value),
);

const optionItems = options.map(option => (
<SelectItem
key={option.value}
option={option}
isSelected={selectedOptions.includes(option)}
onPress={onChange}
/>
));
return [selectedOptions, optionItems];
}
60 changes: 60 additions & 0 deletions src/Select/SelectBox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import React from 'react';
import { StyleSheet, View, ScrollView } from 'react-native';
import { original as theme } from '../common/themes';
import { Border } from '../common/styleElements';

import getSelectOptions, { Option } from './SelectBase';

// TODO: multiselect
// TODO: disabled,
// TODO: original scrollbars

type SelectBoxProps = {
options: Array<Option>;
value: [any] | any;
// disabled?: boolean;
// TODO: what to put below?
onChange: () => void;
style?: Object;
};

const SelectBox = ({
value,
options = [],
// disabled = false,
onChange,
style,
}: SelectBoxProps) => {
function handleOptionSelect(option: Option) {
onChange(option.value);
}

const [, selectOptions] = getSelectOptions({
options,
values: [value],
onChange: handleOptionSelect,
});

return (
<View style={[styles.wrapper, style]}>
<Border variant='cutout' />
<ScrollView>
<View style={[styles.content]}>{selectOptions}</View>
</ScrollView>
</View>
);
};

export default SelectBox;

const styles = StyleSheet.create({
wrapper: {
paddingVertical: 4,
paddingHorizontal: 4,
backgroundColor: theme.canvas,
},
content: {
backgroundColor: theme.canvas,
padding: 2,
},
});
3 changes: 2 additions & 1 deletion src/Select/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { default } from './Select';
export { default as Select } from './Select';
export { default as SelectBox } from './SelectBox';
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export { default as Checkbox } from './Checkbox';
export { default as Radio } from './Radio';
export { default as Fieldset } from './Fieldset';
export { default as Progress } from './Progress';
export { default as Select } from './Select';
export { Select, SelectBox } from './Select';
export { default as Desktop } from './Desktop';
export { default as Menu } from './Menu';
export { default as Tabs } from './Tabs';
Expand Down

0 comments on commit 38094ba

Please sign in to comment.