feat(ui-components) Add button component (#11868)

This commit is contained in:
Robert Pintilii
2022-07-20 09:19:59 +03:00
committed by GitHub
parent 718d32990d
commit b08ed3ade4
21 changed files with 365 additions and 349 deletions

View File

@@ -0,0 +1,195 @@
import { makeStyles } from '@material-ui/core';
import clsx from 'clsx';
import React from 'react';
import Icon from '../../icons/components/Icon';
import { BUTTON_TYPES } from '../../react/constants';
import { withPixelLineHeight } from '../../styles/functions.web';
import { ButtonProps } from './types';
interface IButtonProps extends ButtonProps {
/**
* Whether or not the button should be full width.
*/
fullWidth?: boolean,
/**
* The id of the button.
*/
id?: string;
/**
* Click callback.
*/
onClick: () => void;
/**
* Which size the button should be.
*/
size?: 'small' | 'medium' | 'large';
}
const useStyles = makeStyles((theme: any) => {
return {
button: {
backgroundColor: theme.palette.action01,
color: theme.palette.text01,
borderRadius: theme.shape.borderRadius,
padding: '10px 16px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
border: 0,
...withPixelLineHeight(theme.typography.bodyShortBold),
transition: 'background .2s',
cursor: 'pointer',
'&:hover': {
backgroundColor: theme.palette.action01Hover
},
'&:active': {
backgroundColor: theme.palette.action01Active
},
'&:focus': {
outline: 0,
boxShadow: `0px 0px 0px 2px ${theme.palette.focus01}`
},
'& svg': {
fill: theme.palette.icon01
}
},
primary: {},
secondary: {
backgroundColor: theme.palette.action02,
color: theme.palette.text04,
'&:hover': {
backgroundColor: theme.palette.action02Hover
},
'&:active': {
backgroundColor: theme.palette.action02Active
},
'& svg': {
fill: theme.palette.icon04
}
},
tertiary: {
backgroundColor: theme.palette.action03,
'&:hover': {
backgroundColor: theme.palette.action03Hover
},
'&:active': {
backgroundColor: theme.palette.action03Active
}
},
destructive: {
backgroundColor: theme.palette.actionDanger,
'&:hover': {
backgroundColor: theme.palette.actionDangerHover
},
'&:active': {
backgroundColor: theme.palette.actionDangerActive
}
},
disabled: {
backgroundColor: theme.palette.disabled01,
color: theme.palette.text03,
'&:hover': {
backgroundColor: theme.palette.disabled01,
color: theme.palette.text03
},
'&:active': {
backgroundColor: theme.palette.disabled01,
color: theme.palette.text03
},
'& svg': {
fill: theme.palette.icon03
}
},
iconButton: {
padding: '10px'
},
textWithIcon: {
marginLeft: `${theme.spacing(2)}px`
},
small: {
padding: '8px 16px',
...withPixelLineHeight(theme.typography.labelBold),
'&.iconButton': {
padding: '6px'
}
},
medium: {},
large: {
padding: '13px 16px',
...withPixelLineHeight(theme.typography.bodyShortBoldLarge),
'&.iconButton': {
padding: '14px'
}
},
fullWidth: {
width: '100%'
}
};
});
const Button = ({
accessibilityLabel,
disabled,
fullWidth,
icon,
id,
label,
onClick,
size = 'medium',
type = BUTTON_TYPES.PRIMARY
}: IButtonProps) => {
const styles = useStyles();
return (
<button
aria-label = { accessibilityLabel }
className = { clsx(styles.button, styles[type],
disabled && styles.disabled,
icon && !label && `${styles.iconButton} iconButton`,
styles[size], fullWidth && styles.fullWidth) }
disabled = { disabled }
{ ...(id ? { id } : {}) }
onClick = { onClick }
type = 'button'>
{icon && <Icon
size = { 20 }
src = { icon } />}
{label && <span className = { icon ? styles.textWithIcon : '' }>{label}</span>}
</button>
);
};
export default Button;

View File

@@ -0,0 +1,29 @@
import { BUTTON_TYPES } from '../../react/constants';
export interface ButtonProps {
/**
* Label used for accessibility.
*/
accessibilityLabel: string;
/**
* Whether or not the button is disabled.
*/
disabled?: boolean;
/**
* The icon to be displayed on the button.
*/
icon?: Function;
/**
* The text to be displayed on the button.
*/
label?: string;
/**
* The type of button to be displayed.
*/
type?: BUTTON_TYPES;
}

View File

@@ -1,8 +1,10 @@
// @flow
/* eslint-disable import/order */
import React, { useCallback } from 'react';
// @ts-ignore
import { Container } from '../../react/base';
// @ts-ignore
import { styleTypeToObject } from '../../styles';
type Props = {
@@ -15,7 +17,7 @@ type Props = {
/**
* Color of the icon (if not provided by the style object).
*/
color?: ?string,
color?: string,
/**
* Id prop (mainly for autotests).
@@ -35,7 +37,7 @@ type Props = {
/**
* The size of the icon (if not provided by the style object).
*/
size?: ?number | string,
size?: number | string,
/**
* The preloaded icon component to render.
@@ -82,12 +84,12 @@ type Props = {
*/
ariaControls?: string,
/**
/**
* TabIndex for the Icon.
*/
tabIndex?: number,
/**
/**
* Role for the Icon.
*/
role?: string,
@@ -110,7 +112,7 @@ export const DEFAULT_SIZE = navigator.product === 'ReactNative' ? 36 : 22;
* Implements an Icon component that takes a loaded SVG file as prop and renders it as an icon.
*
* @param {Props} props - The props of the component.
* @returns {Reactelement}
* @returns {ReactElement}
*/
export default function Icon(props: Props) {
const {

View File

@@ -1,5 +1,3 @@
// @flow
export { default as IconAdd } from './add.svg';
export { default as IconAddPeople } from './link.svg';
export { default as IconArrowBack } from './arrow_back.svg';

View File

@@ -11,13 +11,13 @@ import {
import BaseTheme from '../../../ui/components/BaseTheme.native';
// @ts-ignore
import { BUTTON_MODES, BUTTON_TYPES } from '../../constants';
import { ButtonProps } from '../../types';
import { IButtonProps } from '../../types';
// @ts-ignore
import styles from './styles';
const Button: React.FC<ButtonProps> = ({
const Button: React.FC<IButtonProps> = ({
accessibilityLabel,
color: buttonColor,
disabled,
@@ -27,7 +27,7 @@ const Button: React.FC<ButtonProps> = ({
onPress,
style,
type
}: ButtonProps) => {
}: IButtonProps) => {
const { t } = useTranslation();
const { CONTAINED } = BUTTON_MODES;
const { DESTRUCTIVE, PRIMARY, SECONDARY, TERTIARY } = BUTTON_TYPES;

View File

@@ -1,5 +1,3 @@
// @flow
/**
* Z-index for components that are to be rendered like an overlay, to be over
* everything, such as modal-type of components, or dialogs.
@@ -9,12 +7,12 @@ export const OVERLAY_Z_INDEX = 1000;
/**
* The types of the buttons.
*/
export const BUTTON_TYPES = {
PRIMARY: 'primary',
SECONDARY: 'secondary',
TERTIARY: 'tertiary',
DESTRUCTIVE: 'destructive'
};
export enum BUTTON_TYPES {
PRIMARY = 'primary',
SECONDARY = 'secondary',
TERTIARY = 'tertiary',
DESTRUCTIVE = 'destructive'
}
/**
* The modes of the buttons.

View File

@@ -1,13 +1,10 @@
export interface ButtonProps {
accessibilityLabel?: string;
import { ButtonProps } from '../components/common/types';
export interface IButtonProps extends ButtonProps {
color?: string;
disabled?: boolean;
icon?: JSX.Element;
label?: string;
labelStyle?: Object|undefined;
onPress?: Function;
style?: Object|undefined;
type?: string;
}
export interface IconButtonProps {

View File

@@ -1,7 +1,7 @@
// @flow
import { type StyleType } from './functions.any';
// @ts-ignore
import { StyleType } from './functions.any';
// @ts-ignore
export * from './functions.any';
/**
@@ -32,7 +32,7 @@ export function getFixedPlatformStyle(style: StyleType): StyleType {
* @param {Object} base - The base object containing the `lineHeight` property.
* @returns {Object}
*/
export function withPixelLineHeight(base: Object): Object {
export function withPixelLineHeight(base: any): Object {
return {
...base,
lineHeight: `${base.lineHeight}px`