## Button
- Remove props withoutHoverStyle
refactor hover impl with independent layer, so that hover-color won't affect the background even if is overridden outside
- Update `type` (renamed to `variant`):
- remove `processing` and `warning`
- rename `default` with `secondary`
- Remove `shape` props
- Remove `icon` and `iconPosition`, replaced with `prefix: ReactNode` and `suffix: ReactNode`
- Integrate tooltip for more convenient usage
- New Storybook document
- Focus style
## IconButton
- A Wrapper base on `<Button />`
- Override Button size and variant
- size: `'12' | '14' | '16' | '20' | '24' | number`
These presets size are referenced from the design system.
- variant: `'plain' | 'solid' | 'danger' | 'custom'`
- Inset icon via Button 's prefix
## Fix
- fix some button related issues
- close AF-1159, AF-1160, AF-1161, AF-1162, AF-1163, AF-1158, AF-1157
## Storybook

260 lines
6.8 KiB
TypeScript
260 lines
6.8 KiB
TypeScript
import { cssVar } from '@toeverything/theme';
|
|
import { cssVarV2 } from '@toeverything/theme/v2';
|
|
import { createVar, globalStyle, style } from '@vanilla-extract/css';
|
|
|
|
// Using variables can override externally, without considering the priority of selectors.
|
|
// size vars
|
|
export const hVar = createVar('height');
|
|
export const wVar = createVar('width');
|
|
export const iconSizeVar = createVar('iconSize');
|
|
const gapVar = createVar('gap');
|
|
const paddingVar = createVar('padding');
|
|
const fontSizeVar = createVar('fontSize');
|
|
const fontWeightVar = createVar('fontWeight');
|
|
const lineHeightVar = createVar('lineHeight');
|
|
const shadowVar = createVar('shadow');
|
|
|
|
// style vars
|
|
const bgVar = createVar('bg');
|
|
const textVar = createVar('fg');
|
|
const iconColorVar = createVar('icon');
|
|
const borderColorVar = createVar('border');
|
|
const borderWidthVar = createVar('borderWidth');
|
|
|
|
export const button = style({
|
|
vars: {
|
|
// default vars
|
|
[gapVar]: '4px',
|
|
[wVar]: 'unset',
|
|
[hVar]: 'unset',
|
|
[borderWidthVar]: '1px',
|
|
},
|
|
|
|
flexShrink: 0,
|
|
position: 'relative',
|
|
display: 'inline-flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
userSelect: 'none',
|
|
outline: 0,
|
|
borderRadius: 8,
|
|
transition: 'all .3s',
|
|
cursor: 'pointer',
|
|
['WebkitAppRegion' as string]: 'no-drag',
|
|
|
|
// hover layer
|
|
':before': {
|
|
content: '""',
|
|
position: 'absolute',
|
|
width: '100%',
|
|
height: '100%',
|
|
transition: 'inherit',
|
|
borderRadius: 'inherit',
|
|
opacity: 0,
|
|
left: '50%',
|
|
top: '50%',
|
|
transform: 'translate(-50%, -50%)',
|
|
backgroundColor: cssVarV2('layer/background/hoverOverlay'),
|
|
borderColor: 'transparent',
|
|
pointerEvents: 'none',
|
|
borderWidth: 'inherit',
|
|
borderStyle: 'inherit',
|
|
},
|
|
|
|
// style
|
|
backgroundColor: bgVar,
|
|
color: textVar,
|
|
boxShadow: shadowVar,
|
|
borderWidth: borderWidthVar,
|
|
borderStyle: 'solid',
|
|
borderColor: borderColorVar,
|
|
|
|
// size
|
|
width: wVar,
|
|
height: hVar,
|
|
gap: gapVar,
|
|
padding: paddingVar,
|
|
fontSize: fontSizeVar,
|
|
fontWeight: fontWeightVar,
|
|
lineHeight: lineHeightVar,
|
|
|
|
selectors: {
|
|
'&:hover:before': { opacity: 1 },
|
|
'&[data-block]': { display: 'flex' },
|
|
|
|
// size
|
|
'&[data-size="default"]': {
|
|
vars: {
|
|
[hVar]: '28px', // line-height + paddingY * 2 (to ignore border width)
|
|
[paddingVar]: '0px 8px',
|
|
[iconSizeVar]: '16px',
|
|
[paddingVar]: '4px 12px',
|
|
[fontSizeVar]: cssVar('fontXs'),
|
|
[fontWeightVar]: '500',
|
|
[lineHeightVar]: '20px',
|
|
},
|
|
},
|
|
'&[data-size="large"]': {
|
|
vars: {
|
|
[hVar]: '32px',
|
|
[paddingVar]: '0px 8px',
|
|
[iconSizeVar]: '20px',
|
|
[paddingVar]: '4px 12px',
|
|
[fontSizeVar]: '15px',
|
|
[fontWeightVar]: '500',
|
|
[lineHeightVar]: '24px',
|
|
},
|
|
},
|
|
'&[data-size="extraLarge"]': {
|
|
vars: {
|
|
[hVar]: '40px',
|
|
[paddingVar]: '0px 8px',
|
|
[iconSizeVar]: '24px',
|
|
[paddingVar]: '8px 18px',
|
|
[fontSizeVar]: '15',
|
|
[fontWeightVar]: '600',
|
|
[lineHeightVar]: '24px',
|
|
},
|
|
},
|
|
|
|
// type
|
|
'&[data-variant="primary"]': {
|
|
vars: {
|
|
[bgVar]: cssVarV2('button/primary'),
|
|
[textVar]: cssVarV2('button/pureWhiteText'),
|
|
[iconColorVar]: cssVarV2('button/pureWhiteText'),
|
|
[borderColorVar]: cssVarV2('button/innerBlackBorder'),
|
|
},
|
|
},
|
|
'&[data-variant="secondary"]': {
|
|
vars: {
|
|
[bgVar]: cssVarV2('button/secondary'),
|
|
[textVar]: cssVarV2('text/primary'),
|
|
[iconColorVar]: cssVarV2('icon/primary'),
|
|
[borderColorVar]: cssVarV2('layer/border'),
|
|
},
|
|
},
|
|
'&[data-variant="plain"]': {
|
|
vars: {
|
|
[bgVar]: 'transparent',
|
|
[textVar]: cssVarV2('text/primary'),
|
|
[iconColorVar]: cssVarV2('icon/primary'),
|
|
[borderColorVar]: 'transparent',
|
|
[borderWidthVar]: '0px',
|
|
},
|
|
},
|
|
'&[data-variant="error"]': {
|
|
vars: {
|
|
[bgVar]: cssVarV2('button/error'),
|
|
[textVar]: cssVarV2('button/pureWhiteText'),
|
|
[iconColorVar]: cssVarV2('button/pureWhiteText'),
|
|
[borderColorVar]: cssVarV2('button/innerBlackBorder'),
|
|
},
|
|
},
|
|
'&[data-variant="success"]': {
|
|
vars: {
|
|
[bgVar]: cssVarV2('button/success'),
|
|
[textVar]: cssVarV2('button/pureWhiteText'),
|
|
[iconColorVar]: cssVarV2('button/pureWhiteText'),
|
|
[borderColorVar]: cssVarV2('button/innerBlackBorder'),
|
|
},
|
|
},
|
|
|
|
// disabled
|
|
'&[data-disabled]': {
|
|
cursor: 'not-allowed',
|
|
opacity: 0.5,
|
|
},
|
|
|
|
// default keyboard focus style
|
|
'&:focus-visible::after': {
|
|
content: '""',
|
|
width: '100%',
|
|
height: '100%',
|
|
position: 'absolute',
|
|
top: 0,
|
|
left: 0,
|
|
borderRadius: 'inherit',
|
|
boxShadow: `0 0 0 1px ${cssVarV2('layer/insideBorder/primary')}`,
|
|
},
|
|
},
|
|
});
|
|
export const content = style({
|
|
// in case that width is specified by parent and text is too long
|
|
textOverflow: 'ellipsis',
|
|
whiteSpace: 'nowrap',
|
|
overflow: 'hidden',
|
|
});
|
|
|
|
export const icon = style({
|
|
flexShrink: 0,
|
|
// There are two kinds of icon size:
|
|
// 1. control by props: width and height
|
|
width: iconSizeVar,
|
|
height: iconSizeVar,
|
|
// 2. width/height is set to `1em`
|
|
fontSize: iconSizeVar,
|
|
color: iconColorVar,
|
|
});
|
|
globalStyle(`${icon} > svg`, {
|
|
width: '100%',
|
|
height: '100%',
|
|
display: 'block',
|
|
});
|
|
|
|
export const iconButton = style({
|
|
vars: {
|
|
[paddingVar]: '2px',
|
|
// TODO(@CatsJuice): Replace with theme variables when ready
|
|
'--shadow':
|
|
'0px 0px 1px 0px rgba(0, 0, 0, 0.12), 0px 1px 5px 0px rgba(0, 0, 0, 0.12)',
|
|
},
|
|
borderRadius: 4,
|
|
selectors: {
|
|
'[data-theme="dark"] &': {
|
|
vars: {
|
|
'--shadow':
|
|
'0px 0px 1px 0px rgba(0, 0, 0, 0.66), 0px 1px 5px 0px rgba(0, 0, 0, 0.72)',
|
|
},
|
|
},
|
|
'&[data-icon-variant="plain"]': {
|
|
vars: {
|
|
[bgVar]: 'transparent',
|
|
[iconColorVar]: cssVarV2('icon/primary'),
|
|
[borderColorVar]: 'transparent',
|
|
[borderWidthVar]: '0px',
|
|
},
|
|
},
|
|
'&[data-icon-variant="danger"]': {
|
|
vars: {
|
|
[bgVar]: 'transparent',
|
|
[iconColorVar]: cssVarV2('icon/primary'),
|
|
[borderColorVar]: 'transparent',
|
|
[borderWidthVar]: '0px',
|
|
},
|
|
},
|
|
'&[data-icon-variant="danger"]:hover': {
|
|
vars: {
|
|
[bgVar]: cssVar('backgroundErrorColor'),
|
|
[iconColorVar]: cssVar('errorColor'),
|
|
},
|
|
},
|
|
// disable hover layer for danger type
|
|
'&[data-icon-variant="danger"]:hover:before': {
|
|
opacity: 0,
|
|
},
|
|
'&[data-icon-variant="solid"]': {
|
|
vars: {
|
|
[bgVar]: cssVarV2('button/iconButtonSolid'),
|
|
[iconColorVar]: cssVarV2('icon/primary'),
|
|
[borderColorVar]: 'transparent',
|
|
[shadowVar]: 'var(--shadow)',
|
|
},
|
|
},
|
|
|
|
'&[data-icon-size="24"]': {
|
|
vars: { [paddingVar]: '4px' },
|
|
},
|
|
},
|
|
});
|