Skip to content

Commit

Permalink
feat(snackbar): adding snackbar with some basic funcionalities
Browse files Browse the repository at this point in the history
DSY-1406
  • Loading branch information
kenjinino authored Sep 22, 2020
1 parent 3d51b69 commit 964eb25
Show file tree
Hide file tree
Showing 10 changed files with 646 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,7 @@ lib/assets/fonts/natds-icons.*
# files generated automatically from .md
storybook-web/docs
storybook-web/static/dist/*

# Vim
*.swp
*.swo
21 changes: 21 additions & 0 deletions src/components/Snackbar/Snackbar.device.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { storiesOf } from '@storybook/react-native';
import {
interactive,
standard,
info,
warning,
error,
success,
multiline,
multilineWithButton,
} from './Snackbar.stories';

storiesOf('Snackbar', module)
.add('interactive', interactive)
.add('standard', standard)
.add('info', info)
.add('warning', warning)
.add('error', error)
.add('success', success)
.add('multiline', multiline)
.add('multiline with button', multilineWithButton);
116 changes: 116 additions & 0 deletions src/components/Snackbar/Snackbar.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import React, { useState } from 'react';
import { View, Button } from 'react-native';
import { text, select, number } from '@storybook/addon-knobs';
import { Snackbar, SnackbarType } from './Snackbar';

export default {
component: Snackbar,
parameters: {
componentSubtitle:
'Snackar',
},
title: 'Components|Snackbar',
};

const snackbarTypeOptions = ['error', 'info', 'standard', 'success', 'warning'];

export const interactive = () => {
const [open, setOpen] = useState(false);

return (
<View style={{ backgroundColor: 'gainsboro', flex: 1, height: 200 }}>
<Snackbar
message={text('message', 'A short snackbar message')}
buttonText={text('button text', 'ok')}
type={select('type', snackbarTypeOptions, 'standard') as SnackbarType}
autoHideDuration={number('auto hide duration', 5000)}
open={open}
onClose={() => setOpen(false)} />
<Button onPress={() => setOpen(!open)} title='open snackbar' />
</View>
);
};

export const standard = () => {
const [open, setOpen] = useState(false);
const message = 'A short snackbar message';

return (
<View style={{ backgroundColor: 'gainsboro', flex: 1, height: 200 }}>
<Snackbar message={message} open={open} onClose={() => setOpen(false)} />
<Button onPress={() => setOpen(!open)} title='open standard snackbar' />
</View>
);
};

export const info = () => {
const [open, setOpen] = useState(false);
const message = 'A short snackbar message';

return (
<View style={{ backgroundColor: 'gainsboro', flex: 1, height: 200 }}>
<Snackbar message={message} open={open} onClose={() => setOpen(false)} type="info" />
<Button onPress={() => setOpen(!open)} title='open info snackbar' />
</View>
);
};

export const warning = () => {
const [open, setOpen] = useState(false);
const message = 'A short snackbar message';

return (
<View style={{ backgroundColor: 'gainsboro', flex: 1, height: 200 }}>
<Snackbar message={message} open={open} onClose={() => setOpen(false)} type="warning" />
<Button onPress={() => setOpen(!open)} title='open warning snackbar' />
</View>
);
};

export const error = () => {
const [open, setOpen] = useState(false);
const message = 'A short snackbar message';

return (
<View style={{ backgroundColor: 'gainsboro', flex: 1, height: 200 }}>
<Snackbar message={message} open={open} onClose={() => setOpen(false)} type="error" />
<Button onPress={() => setOpen(!open)} title='open error snackbar' />
</View>
);
};

export const success = () => {
const [open, setOpen] = useState(false);
const message = 'A short snackbar message';

return (
<View style={{ backgroundColor: 'gainsboro', flex: 1, height: 200 }}>
<Snackbar message={message} open={open} onClose={() => setOpen(false)} type="success" />
<Button onPress={() => setOpen(!open)} title='open success snackbar' />
</View>
);
};

export const multiline = () => {
const [open, setOpen] = useState(false);
const message = 'A longer message to hopefully show how it behaves when there is a multiline snackbar. The text will be truncated and the missing text at the end of the line will be indicated by an ellipsis glyph';

return (
<View style={{ backgroundColor: 'gainsboro', flex: 1, height: 200 }}>
<Snackbar message={message} open={open} onClose={() => setOpen(false)} type="standard" />
<Button onPress={() => setOpen(!open)} title='open multiline snackbar' />
</View>
);
};

export const multilineWithButton = () => {
const [open, setOpen] = useState(false);
const message = 'A longer message to hopefully show how it behaves when there is a multiline snackbar. The text will be truncated and the missing text at the end of the line will be indicated by an ellipsis glyph';

return (
<View style={{ backgroundColor: 'gainsboro', flex: 1, height: 200 }}>
<Snackbar message={message} open={open} onClose={() => setOpen(false)} type="standard" buttonText="ok" />
<Button onPress={() => setOpen(!open)} title='open multiline snackbar with button' />
</View>
);
};
117 changes: 117 additions & 0 deletions src/components/Snackbar/Snackbar.styles.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import styled from 'styled-components/native';
import { TextProps, NativeSyntheticEvent, TargetedEvent } from 'react-native';
import { SnackbarType } from './Snackbar';
import { Theme } from '../../common/themeSelectors';

const getBackgroundColorByType = (theme: Theme, type: SnackbarType) => {
switch (type) {
case 'info':
return theme.colorTokens.colorLink;
case 'warning':
return theme.colorTokens.colorWarning;
case 'error':
return theme.colorTokens.colorAlert;
case 'success':
return theme.colorTokens.colorSuccess;
default:
return theme.colorTokens.colorOnSurface;
}
};

export const getColorByType = (theme: Theme, type: SnackbarType) => {
switch (type) {
case 'info':
return theme.colorTokens.colorOnLink;
case 'warning':
return theme.colorTokens.colorOnWarning;
case 'error':
return theme.colorTokens.colorOnAlert;
case 'success':
return theme.colorTokens.colorOnSuccess;
default:
return theme.colorTokens.colorSurface;
}
};

export const getColorNameByType = (type: SnackbarType) => {
switch (type) {
case 'info':
return 'onLink';
case 'warning':
return 'onWarning';
case 'error':
return 'onAlert';
case 'success':
return 'onSuccess';
default:
return 'surface';
}
};

interface SnackbarButtonWrapperProps { isTwoLineAction?: boolean; }

export const SnackbarButtonWrapper = styled.View<SnackbarButtonWrapperProps>`
marginTop: ${({ isTwoLineAction }) => (isTwoLineAction ? '0px' : '4px')};
marginBottom: 4px;
marginRight: 4px;
marginLeft: 4px;
`;

interface SnackbarWrapperProps {
theme: Theme;
type: SnackbarType;
}

export const SnackbarWrapper = styled.View<SnackbarWrapperProps>(({ theme, type }) => ({
alignItems: 'center',
backgroundColor: getBackgroundColorByType(theme, type),
borderRadius: theme.radius.medium,
bottom: 0,
flexDirection: 'row',
flexWrap: 'wrap',
justifyContent: 'flex-end',
left: 0,
marginBottom: theme.spacing.spacingSmall,
marginLeft: theme.spacing.spacingSmall,
marginRight: theme.spacing.spacingSmall,
position: 'absolute',
right: 0,
}));

// begin - onTextLayout missing typings @0.62.2
// TODO: remove this block when upgrading @types/react-native
interface TextLayoutLine {
ascender: number;
capHeight: number;
descender: number;
height: number;
text: string;
width: number;
x: number;
xHeight: number;
y: number;
}

interface TextLayoutEventData extends TargetedEvent {
lines: TextLayoutLine[];
}
// end - onTextLayout missing typings @0.62.2

interface SnackbarTextProps extends TextProps {
/**
* Invoked on Text layout
*/
onTextLayout?: (event: NativeSyntheticEvent<TextLayoutEventData>) => void;
type: SnackbarType;
isTwoLineAction?: boolean;
}

export const SnackbarText = styled.Text<SnackbarTextProps>`
color: ${({ theme, type }) => getColorByType(theme, type)};
flexGrow: 1;
paddingBottom: ${({ isTwoLineAction }) => (isTwoLineAction ? 8 : 16)}px;
paddingLeft: 16px;
paddingRight: 16px;
paddingTop: 16px;
fontSize: 14px;
`;
Loading

0 comments on commit 964eb25

Please sign in to comment.