Skip to content

Commit

Permalink
feat(scrollview): add ScrollView component
Browse files Browse the repository at this point in the history
  • Loading branch information
Artur Bien committed Dec 5, 2020
1 parent 38094ba commit aa5682f
Show file tree
Hide file tree
Showing 11 changed files with 262 additions and 22 deletions.
35 changes: 35 additions & 0 deletions example/src/examples/ButtonExample.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ const ButtonExample = () => {
return (
<Container>
<Container.Section title='Default'>
<Button
primary
variant='default'
onPress={() => console.warn('Pressed')}
>
Primary
</Button>
<Button variant='default' onPress={() => console.warn('Pressed')}>
Default
</Button>
Expand All @@ -27,6 +34,34 @@ const ButtonExample = () => {
</Button>
</Container.Section>

<Container.Section title='Outside'>
<Button
primary
variant='outside'
onPress={() => console.warn('Pressed')}
>
Primary
</Button>
<Button variant='outside' onPress={() => console.warn('Pressed')}>
Default
</Button>
<Button
active
variant='outside'
onPress={() => console.warn('Pressed')}
>
Active
</Button>

<Button
variant='outside'
disabled
onPress={() => console.warn('Pressed')}
>
Disabled
</Button>
</Container.Section>

<Container.Section title='Primary'>
<Button
primary
Expand Down
9 changes: 9 additions & 0 deletions example/src/examples/SelectExample.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@ const SelectExample = () => {
style={[{ width: 150 }]}
/>
</Fieldset>
<Fieldset label='Custom menu height:' style={[{ padding: 20 }]}>
<Select
menuMaxHeight={130}
options={options}
value={value}
onChange={newValue => setValue(newValue)}
style={[{ width: 150 }]}
/>
</Fieldset>
</Panel>
);
};
Expand Down
9 changes: 7 additions & 2 deletions src/Button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export type ButtonSizes = 'sm' | 'md' | 'lg';
type ButtonProps = {
children: React.ReactNode;
onPress?: () => void;
variant?: 'menu' | 'flat' | 'default';
variant?: 'menu' | 'flat' | 'default' | 'outside';
size?: ButtonSizes;
style?: StyleProp<ViewStyle>;
disabled?: boolean;
Expand Down Expand Up @@ -107,7 +107,7 @@ export default Button;

type BorderProps = {
isPressed?: boolean;
variant?: 'menu' | 'flat' | 'default';
variant?: 'menu' | 'flat' | 'default' | 'outside';
primary?: boolean;
active?: boolean;
};
Expand All @@ -128,6 +128,11 @@ const Borders = ({
outer = [border.defaultOuter];
inner = [border.defaultInner];
focus = isPressed ? [border.focusOutline] : [];
} else if (variant === 'outside') {
wrapper = primary ? [border.outline] : [];
outer = [border.outsideOuter];
inner = [border.outsideInner];
focus = isPressed ? [border.focusOutline] : [];
} else if (variant === 'menu' && (active || isPressed)) {
wrapper = [border.well];
}
Expand Down
18 changes: 7 additions & 11 deletions src/Cutout/Cutout.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
import React from 'react';
import {
StyleSheet,
View,
ScrollView,
StyleProp,
ViewStyle,
} from 'react-native';
import { StyleSheet, View, StyleProp, ViewStyle } from 'react-native';
import { Border } from '../common/styleElements';

import { ScrollView } from '..';

export const testId = 'cutout';

type Props = {
Expand All @@ -28,15 +24,15 @@ const Cutout = ({ children, style = {} }: Props) => {
};

const styles = StyleSheet.create({
content: {
padding: 4,
},
wrapper: {
width: '100%',
height: '100%',
height: 100,
// to compensate for borders
padding: 4,
},
content: {
padding: 4,
},
});

export default Cutout;
File renamed without changes.
182 changes: 182 additions & 0 deletions src/ScrollView/ScrollView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
import React from 'react';
import {
StyleSheet,
View,
ScrollView as RNScrollView,
ViewStyle,
ImageBackground,
Image,
} from 'react-native';
import { original as theme } from '../common/themes';

import { Panel, Button } from '..';

type ScrollViewProps = React.ComponentProps<typeof RNScrollView> & {
style?: ViewStyle;
children: React.ReactNode;
};

const scrollbarSize = 30;

const Icon = (
<Image
// border to compensate for Border
style={[
{
width: 18,
height: 18,
marginTop: 6,
},
]}
source={{
uri:
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAALElEQVQoU2NkIAIwEqGGgWRF/7GYCjYE3SRkhXA5bNaBFKKIk+wmnB4lyiQAAsgDCqkPxTcAAAAASUVORK5CYII=',
}}
/>
);

const ScrollView = ({ children, style, ...rest }: ScrollViewProps) => {
const scrollView = React.useRef(null);
const [contentOffset, setContentOffset] = React.useState({ x: 0, y: 0 });
const [contentSize, setContentSize] = React.useState(0);
const [scrollViewHeight, setScrollViewHeight] = React.useState(0);

const scrollElementHeightPercent = 100 * (scrollViewHeight / contentSize);

const scrollPerc =
(contentOffset.y / (contentSize - scrollViewHeight)) *
(100 - scrollElementHeightPercent);

const thumbPosition = Math.max(
0,
Math.min(100 - scrollElementHeightPercent, Math.round(scrollPerc || 0)),
);

const moveScroll = (direction: -1 | 1) => {
if (scrollView.current) {
scrollView.current.scrollTo({ y: contentOffset.y + 24 * direction });
}
};

return (
<View style={[styles.wrapper, style]}>
<View style={[styles.content]}>
<RNScrollView
showsVerticalScrollIndicator={false}
scrollEventThrottle={10}
ref={scrollView}
onScroll={e => {
setContentOffset(e.nativeEvent.contentOffset);
}}
onContentSizeChange={(_, height) => {
setContentSize(height);
}}
onLayout={e => {
setScrollViewHeight(e.nativeEvent.layout.height);
}}
{...rest}
>
{children}
</RNScrollView>
</View>
{contentSize > scrollViewHeight && (
<View style={[styles.scrollbarTrack]}>
<ImageBackground
style={[styles.background]}
imageStyle={{
resizeMode: 'repeat',
}}
source={{
// TODO: create util function for generating checkered background
uri:
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAIUlEQVQoU2P8////fwYkwMjIyIjCp4MCZPtAbAwraa8AAEGrH/nfAIhgAAAAAElFTkSuQmCC',
}}
/>
<Button
variant='outside'
onPress={() => moveScroll(-1)}
style={[styles.scrollbarButton]}
>
<View
style={{
justifyContent: 'center',
alignItems: 'center',
// flex: 1,
transform: [{ translateY: 6 }, { rotate: '180deg' }],
}}
>
{Icon}
</View>
</Button>
<View style={[styles.scrollbar]}>
<Panel
variant='outside'
style={[
styles.scrollbarBar,
{
position: 'absolute',
top: `${thumbPosition}%`,
height: `${scrollElementHeightPercent}%`,
},
]}
/>
</View>
<Button
variant='outside'
onPress={() => moveScroll(1)}
style={[styles.scrollbarButton]}
>
<View
style={{
justifyContent: 'center',
alignItems: 'center',
// flex: 1,
}}
>
{Icon}
</View>
</Button>
</View>
)}
</View>
);
};

export default ScrollView;

const styles = StyleSheet.create({
wrapper: {
display: 'flex',
flexDirection: 'row',
height: 'auto',
position: 'relative',
},
content: {
flexGrow: 1,
},
scrollbarTrack: {
height: '100%',
backgroundColor: theme.material,
},
scrollbarButton: {
height: scrollbarSize,
width: scrollbarSize,
padding: 0,
},
scrollbar: {
// height: '100%',
width: scrollbarSize,
overflow: 'hidden',
flex: 1,
},
background: {
position: 'absolute',
top: 0,
right: 0,
bottom: 0,
left: 0,
},
scrollbarBar: {
width: '100%',
},
});
1 change: 1 addition & 0 deletions src/ScrollView/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './ScrollView';
24 changes: 16 additions & 8 deletions src/Select/Select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { blockSizes, text, border } from '../common/styles';
import { Border } from '../common/styleElements';

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

const dropdownSymbol = {
default:
Expand All @@ -27,12 +28,14 @@ type SelectProps = {
// TODO: what to put below?
onChange: () => void;
style?: Object;
menuMaxHeight?: number;
};

const Select = ({
value,
options = [],
disabled = false,
menuMaxHeight,
onChange,
style,
}: SelectProps) => {
Expand Down Expand Up @@ -134,10 +137,15 @@ const Select = ({
</View>

{isOpen && (
<View style={[styles.options]}>
{/* <ScrollView> */}
{selectOptions}
{/* </ScrollView> */}
<View
style={[
styles.options,
{
height: menuMaxHeight || 'auto',
},
]}
>
<ScrollView>{selectOptions}</ScrollView>
</View>
)}
</View>
Expand All @@ -147,7 +155,7 @@ const Select = ({

export default Select;

const selectHeight = blockSizes.md + 2;
const selectHeight = blockSizes.md;

const styles = StyleSheet.create({
wrapper: {
Expand Down Expand Up @@ -183,15 +191,15 @@ const styles = StyleSheet.create({
fakeButton: {
position: 'relative',
height: '100%',
width: 33,
width: 30,
padding: 4,
backgroundColor: theme.material,
},
options: {
position: 'absolute',
top: selectHeight,
left: 2,
right: 4,
left: 0,
right: 0,
backgroundColor: theme.canvas,
borderWidth: 2,
borderColor: theme.borderDarkest,
Expand Down
Loading

0 comments on commit aa5682f

Please sign in to comment.