feat: refactor ui components

This commit is contained in:
QiShaoXuan
2022-12-05 22:20:21 +08:00
parent 09767c310a
commit 2ca52c187b
11 changed files with 261 additions and 223 deletions
@@ -0,0 +1,85 @@
import {
HTMLAttributes,
cloneElement,
ReactElement,
Children,
CSSProperties,
forwardRef,
} from 'react';
import { StyledIconButton } from './styles';
const SIZE_SMALL = 'small' as const;
const SIZE_MIDDLE = 'middle' as const;
const SIZE_NORMAL = 'normal' as const;
// TODO: Designer is not sure about the size of the icon button
const SIZE_CONFIG = {
[SIZE_SMALL]: {
iconSize: 16,
areaSize: 24,
},
[SIZE_MIDDLE]: {
iconSize: 20,
areaSize: 28,
},
[SIZE_NORMAL]: {
iconSize: 24,
areaSize: 32,
},
} as const;
export type IconButtonProps = {
size?:
| typeof SIZE_SMALL
| typeof SIZE_MIDDLE
| typeof SIZE_NORMAL
| [number, number];
iconSize?:
| typeof SIZE_SMALL
| typeof SIZE_MIDDLE
| typeof SIZE_NORMAL
| [number, number];
disabled?: boolean;
hoverBackground?: string;
hoverColor?: string;
hoverStyle?: CSSProperties;
children: ReactElement<HTMLAttributes<SVGElement>, 'svg'>;
} & HTMLAttributes<HTMLButtonElement>;
export const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(
(
{
size = 'normal',
iconSize = 'normal',
disabled = false,
children,
...props
},
ref
) => {
const [width, height] = Array.isArray(size)
? size
: [SIZE_CONFIG[size]['areaSize'], SIZE_CONFIG[size]['areaSize']];
const [iconWidth, iconHeight] = Array.isArray(iconSize)
? iconSize
: [SIZE_CONFIG[iconSize]['iconSize'], SIZE_CONFIG[iconSize]['iconSize']];
return (
<StyledIconButton
ref={ref}
disabled={disabled}
width={width}
height={height}
borderRadius={iconWidth / 4}
{...props}
>
{cloneElement(Children.only(children), {
width: iconWidth,
height: iconHeight,
})}
</StyledIconButton>
);
}
);
IconButton.displayName = 'IconButton';
export default IconButton;
+1
View File
@@ -0,0 +1 @@
export * from './icon-button';
+55
View File
@@ -0,0 +1,55 @@
import { absoluteCenter, displayFlex, styled } from '@/styles';
import { CSSProperties } from 'react';
export const StyledIconButton = styled.button<{
width: number;
height: number;
borderRadius: number;
disabled?: boolean;
hoverBackground?: string;
hoverColor?: string;
hoverStyle?: CSSProperties;
}>(
({
theme,
width,
height,
disabled,
hoverBackground,
hoverColor,
hoverStyle,
}) => {
return {
width,
height,
color: theme.colors.iconColor,
...displayFlex('center', 'center'),
position: 'relative',
...(disabled ? { cursor: 'not-allowed', pointerEvents: 'none' } : {}),
transition: 'background .15s',
// TODO: we need to add @emotion/babel-plugin
'::after': {
content: '""',
width,
height,
borderRadius: width / 5,
transition: 'background .15s',
...absoluteCenter({ horizontal: true, vertical: true }),
},
svg: {
position: 'relative',
zIndex: 1,
},
':hover': {
color: hoverColor ?? theme.colors.primaryColor,
'::after': {
background: hoverBackground ?? theme.colors.hoverBackground,
},
...(hoverStyle ?? {}),
},
};
}
);
+2 -1
View File
@@ -1,2 +1,3 @@
export * from './menu';
export { StyledMenuItem as MenuItem } from './styles';
// export { StyledMenuItem as MenuItem } from './styles';
export * from './menu-item';
+35
View File
@@ -0,0 +1,35 @@
import {
cloneElement,
forwardRef,
HTMLAttributes,
PropsWithChildren,
ReactElement,
} from 'react';
import { StyledMenuItem, StyledArrow } from './styles';
export type IconMenuProps = PropsWithChildren<{
isDir?: boolean;
icon?: ReactElement;
}> &
HTMLAttributes<HTMLButtonElement>;
export const MenuItem = forwardRef<HTMLButtonElement, IconMenuProps>(
({ isDir = false, icon, children, ...props }, ref) => {
return (
<StyledMenuItem ref={ref} {...props}>
{icon &&
cloneElement(icon, {
width: 16,
height: 16,
style: {
marginRight: 14,
},
})}
{children}
{isDir ? <StyledArrow /> : null}
</StyledMenuItem>
);
}
);
MenuItem.displayName = 'MenuItem';
export default MenuItem;
+36 -19
View File
@@ -1,5 +1,6 @@
import { styled } from '@/styles';
import { displayFlex, styled } from '@/styles';
import StyledPopperContainer from '../shared/Container';
import { MiddleArrowRightIcon } from '@blocksuite/icons';
export const StyledMenuWrapper = styled(StyledPopperContainer)(({ theme }) => {
return {
@@ -12,23 +13,39 @@ export const StyledMenuWrapper = styled(StyledPopperContainer)(({ theme }) => {
};
});
export const StyledMenuItem = styled('div')<{ popperVisible?: boolean }>(
({ theme, popperVisible }) => {
return {
borderRadius: '5px',
padding: '0 14px',
export const StyledArrow = styled(MiddleArrowRightIcon)(({ theme }) => {
return {
position: 'absolute',
right: 0,
top: 0,
bottom: 0,
margin: 'auto',
};
});
color: popperVisible
? theme.colors.primaryColor
: theme.colors.popoverColor,
backgroundColor: popperVisible
? theme.colors.hoverBackground
: 'transparent',
export const StyledMenuItem = styled.button<{
popperVisible?: boolean;
isDir?: boolean;
}>(({ theme, popperVisible, isDir = false }) => {
return {
width: '100%',
borderRadius: '5px',
padding: '0 14px',
fontSize: '14px',
height: '32px',
...displayFlex('flex-start', 'center'),
cursor: isDir ? 'pointer' : '',
position: 'relative',
color: popperVisible
? theme.colors.primaryColor
: theme.colors.popoverColor,
backgroundColor: popperVisible
? theme.colors.hoverBackground
: 'transparent',
':hover': {
color: theme.colors.primaryColor,
backgroundColor: theme.colors.hoverBackground,
},
};
}
);
':hover': {
color: theme.colors.primaryColor,
backgroundColor: theme.colors.hoverBackground,
},
};
});
+2 -2
View File
@@ -48,11 +48,11 @@ export const StyledTableRow = styled.tr(({ theme }) => {
td: {
transition: 'background .15s',
},
'td:first-child': {
'td:first-of-type': {
borderTopLeftRadius: '10px',
borderBottomLeftRadius: '10px',
},
'td:last-child': {
'td:last-of-type': {
borderTopRightRadius: '10px',
borderBottomRightRadius: '10px',
},