You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

192 lines
5.7 KiB

// deps-lint-skip-all
import type { CSSObject } from '@ant-design/cssinjs';
import { TinyColor } from '@ctrl/tinycolor';
import type { FullToken, GenerateStyle } from '../../_util/theme';
import { genComponentStyleHook, mergeToken, resetComponent } from '../../_util/theme';
export interface ComponentToken {
// FIXME: need to be removed
bgColor: string;
bgColorHover: string;
bgColorSelected: string;
labelColor: string;
labelColorHover: string;
}
interface SegmentedToken extends FullToken<'Segmented'> {
segmentedPaddingHorizontal: number;
segmentedPaddingHorizontalSM: number;
segmentedContainerPadding: number;
}
// ============================== Mixins ==============================
function segmentedDisabledItem(cls: string, token: SegmentedToken): CSSObject {
return {
[`${cls}, ${cls}:hover, ${cls}:focus`]: {
color: token.colorTextDisabled,
cursor: 'not-allowed',
},
};
}
function getSegmentedItemSelectedStyle(token: SegmentedToken): CSSObject {
return {
backgroundColor: token.bgColorSelected,
borderRadius: token.controlRadius,
boxShadow: token.boxShadowSegmentedSelectedItem,
};
}
const segmentedTextEllipsisCss: CSSObject = {
overflow: 'hidden',
// handle text ellipsis
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
wordBreak: 'keep-all',
};
// ============================== Styles ==============================
const genSegmentedStyle: GenerateStyle<SegmentedToken> = (token: SegmentedToken) => {
const { componentCls } = token;
return {
[componentCls]: {
...resetComponent(token),
display: 'inline-block',
padding: token.segmentedContainerPadding,
color: token.labelColor,
backgroundColor: token.bgColor,
borderRadius: token.radiusBase,
transition: `all ${token.motionDurationSlow} ${token.motionEaseInOut}`,
[`${componentCls}-group`]: {
position: 'relative',
display: 'flex',
alignItems: 'stretch',
justifyItems: 'flex-start',
width: '100%',
},
// RTL styles
'&&-rtl': {
direction: 'rtl',
},
// hover/focus styles
[`&:not(${componentCls}-disabled)`]: {
'&:hover, &:focus': {
backgroundColor: token.bgColorHover,
},
},
// block styles
'&&-block': {
display: 'flex',
},
[`&&-block ${componentCls}-item`]: {
flex: 1,
minWidth: 0,
},
// item styles
[`${componentCls}-item`]: {
position: 'relative',
textAlign: 'center',
cursor: 'pointer',
transition: `color ${token.motionDurationSlow} ${token.motionEaseInOut}`,
'&-selected': {
...getSegmentedItemSelectedStyle(token),
color: token.labelColorHover,
},
'&:hover, &:focus': {
color: token.labelColorHover,
},
'&-label': {
minHeight: token.controlHeight - token.segmentedContainerPadding * 2,
lineHeight: `${token.controlHeight - token.segmentedContainerPadding * 2}px`,
padding: `0 ${token.segmentedPaddingHorizontal}px`,
...segmentedTextEllipsisCss,
},
// syntactic sugar to add `icon` for Segmented Item
'&-icon + *': {
marginInlineEnd: token.marginSM / 2,
},
'&-input': {
position: 'absolute',
insetBlockStart: 0,
insetInlineStart: 0,
width: 0,
height: 0,
opacity: 0,
pointerEvents: 'none',
},
},
// size styles
[`&&-lg ${componentCls}-item-label`]: {
minHeight: token.controlHeightLG - token.segmentedContainerPadding * 2,
lineHeight: `${token.controlHeightLG - token.segmentedContainerPadding * 2}px`,
padding: `0 ${token.segmentedPaddingHorizontal}px`,
fontSize: token.fontSizeLG,
},
[`&&-sm ${componentCls}-item-label`]: {
minHeight: token.controlHeightSM - token.segmentedContainerPadding * 2,
lineHeight: `${token.controlHeightSM - token.segmentedContainerPadding * 2}px`,
padding: `0 ${token.segmentedPaddingHorizontalSM}px`,
},
// disabled styles
...segmentedDisabledItem(`&-disabled ${componentCls}-item`, token),
...segmentedDisabledItem(`${componentCls}-item-disabled`, token),
// thumb styles
[`${componentCls}-thumb`]: {
...getSegmentedItemSelectedStyle(token),
position: 'absolute',
insetBlockStart: 0,
insetInlineStart: 0,
width: 0,
height: '100%',
padding: `${token.paddingXXS}px 0`,
},
// transition effect when `appear-active`
[`${componentCls}-thumb-motion-appear-active`]: {
transition: `transform ${token.motionDurationSlow} ${token.motionEaseInOut}, width ${token.motionDurationSlow} ${token.motionEaseInOut}`,
willChange: 'transform, width',
},
},
};
};
// ============================== Export ==============================
export default genComponentStyleHook(
'Segmented',
token => {
const { lineWidthBold, controlLineWidth } = token;
const segmentedToken = mergeToken<SegmentedToken>(token, {
segmentedPaddingHorizontal: token.controlPaddingHorizontal - controlLineWidth,
segmentedPaddingHorizontalSM: token.controlPaddingHorizontalSM - controlLineWidth,
segmentedContainerPadding: lineWidthBold,
});
return [genSegmentedStyle(segmentedToken)];
},
{
bgColor: new TinyColor('#000').setAlpha(0.04).toRgbString(),
bgColorHover: new TinyColor('#000').setAlpha(0.06).toRgbString(),
bgColorSelected: '#fff',
labelColor: new TinyColor('#000').setAlpha(0.65).toRgbString(),
labelColorHover: '#262626',
},
);