refactor: Table to CSS-IN-JS (#35584)

* style: add basic styles of table

* style: add basic border styles of table

* style: add more styles of table

* style: add more styles of table

* style: add pagination and summary styles

* add more styles

* style: add cell-ellipsis styles

* style: add Radius style

* style: add basic styles of table

* style: add basic border styles of table

* style: add more styles of table

* style: add more styles of table

* style: add pagination and summary styles

* add more styles

* style: add cell-ellipsis styles

* style: add Radius style

* style: add sorter style

* style: add sorter style

* style: add filter style

* style: add filter style

* style: add filter style

* style: fix filter and sort style

* style: fix bordered style

* style: fix bordered style

* style: fix bordered style

* style: add size style

* style: fix size style

* style: add selection style

* style: format code

* style: add sticky code

* style: add expand code

* style: add expand code

* style: add expand code

* style: add fixed code

* add fixed style

* style: fix diff place

* style: use number as px string

* chore: improve function name

* chore: use token

* style: rtl styles

* chore: fix marigin and padding logical properties

* fix: rtl styles

* fix: table filter dropdown style

* chore: remove useStyle

* chore: revert classNames

* fix: test case

* fix shadow in rtl

* Apply suggestions from code review

* chore: sub filter tree

* style: fix tree dropdown padding

Co-authored-by: zombiej <smith3816@gmail.com>
This commit is contained in:
afc163 2022-05-31 10:10:35 +08:00 committed by GitHub
parent 47493c0e90
commit 9b95a30ec9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 2125 additions and 804 deletions

View File

@ -7,6 +7,7 @@ import type { ComponentToken as ButtonComponentToken } from '../../button/style'
import type { ComponentToken as CalendarComponentToken } from '../../calendar/style';
import type { ComponentToken as CarouselComponentToken } from '../../carousel/style';
import type { ComponentToken as CascaderComponentToken } from '../../cascader/style';
import type { ComponentToken as CheckboxComponentToken } from '../../checkbox/style';
import type { ComponentToken as DatePickerComponentToken } from '../../date-picker/style';
import type { ComponentToken as DividerComponentToken } from '../../divider/style';
import type { ComponentToken as DropdownComponentToken } from '../../dropdown/style';
@ -72,7 +73,7 @@ export interface OverrideToken {
Breadcrumb?: {};
Carousel?: CarouselComponentToken;
Cascader?: CascaderComponentToken;
Checkbox?: {};
Checkbox?: CheckboxComponentToken;
Collapse?: {};
DatePicker?: DatePickerComponentToken;
Descriptions?: {};
@ -115,6 +116,7 @@ export interface OverrideToken {
Message?: MessageComponentToken;
Upload?: UploadComponentToken;
Tooltip?: {};
Table?: {};
Space?: SpaceComponentToken;
Progress?: ProgressComponentToken;
Transfer?: {};
@ -314,6 +316,7 @@ export interface AliasToken extends Omit<DerivativeToken, OmitDerivativeKey> {
controlOutlineWidth: number;
controlItemBgHover: string; // Note. It also is a color
controlItemBgActive: string; // Note. It also is a color
controlInteractiveSize: number;
// Color
colorBorder: string;

View File

@ -84,6 +84,8 @@ export default function formatToken(derivativeToken: RawMergedToken): AliasToken
controlLineWidth: mergedToken.lineWidth,
controlOutlineWidth: mergedToken.lineWidth * 2,
controlItemBgHover: mergedToken.colorBgBelow2,
// Checkbox size and expand icon size
controlInteractiveSize: mergedToken.controlHeight / 2,
// 👀👀👀👀👀👀👀👀👀 Not align with Derivative 👀👀👀👀👀👀👀👀👀
// FIXME: @arvinxx handle this

View File

@ -1,10 +1,13 @@
// deps-lint-skip-all
import { Keyframes } from '@ant-design/cssinjs';
import type { GenerateStyle, FullToken } from '../../_util/theme';
import { resetComponent, genComponentStyleHook, mergeToken } from '../../_util/theme';
import type { FullToken, GenerateStyle } from '../../_util/theme';
import { genComponentStyleHook, mergeToken, resetComponent } from '../../_util/theme';
export interface ComponentToken {}
interface CheckboxToken extends FullToken<'Checkbox'> {
checkboxCls: string;
checkboxSize: number;
}
// ============================== Motion ==============================
@ -92,8 +95,8 @@ export const genCheckboxStyle: GenerateStyle<CheckboxToken> = token => {
top: 0,
insetInlineStart: 0,
display: 'block',
width: token.fontSizeLG,
height: token.fontSizeLG,
width: token.checkboxSize,
height: token.checkboxSize,
direction: 'ltr',
backgroundColor: token.colorBgComponent,
border: `${token.controlLineWidth}px ${token.controlLineType} ${token.colorBorder}`,
@ -106,8 +109,8 @@ export const genCheckboxStyle: GenerateStyle<CheckboxToken> = token => {
top: '50%',
insetInlineStart: '21.5%',
display: 'table',
width: (token.fontSizeLG / 14) * 5,
height: (token.fontSizeLG / 14) * 8,
width: (token.checkboxSize / 14) * 5,
height: (token.checkboxSize / 14) * 8,
border: `${token.lineWidthBold}px solid ${token.colorBgComponent}`,
borderTop: 0,
borderInlineStart: 0,
@ -241,6 +244,7 @@ export const genCheckboxStyle: GenerateStyle<CheckboxToken> = token => {
export function getStyle(prefixCls: string, token: FullToken<'Checkbox'>) {
const checkboxToken: CheckboxToken = mergeToken<CheckboxToken>(token, {
checkboxCls: `.${prefixCls}`,
checkboxSize: token.controlInteractiveSize,
});
return [genCheckboxStyle(checkboxToken)];

View File

@ -50,6 +50,7 @@ import ColumnGroup from './ColumnGroup';
import warning from '../_util/warning';
import useBreakpoint from '../grid/hooks/useBreakpoint';
import defaultRenderEmpty from '../config-provider/defaultRenderEmpty';
import useStyle from './style';
export { ColumnsType, TablePaginationConfig };
@ -493,14 +494,18 @@ function InternalTable<RecordType extends object = any>(
};
}
// Style
const [wrapSSR, hashId] = useStyle(prefixCls);
const wrapperClassNames = classNames(
`${prefixCls}-wrapper`,
{
[`${prefixCls}-wrapper-rtl`]: direction === 'rtl',
},
className,
hashId,
);
return (
return wrapSSR(
<div ref={ref} className={wrapperClassNames} style={style}>
<Spin spinning={false} {...spinProps}>
{topPaginationNode}
@ -527,7 +532,7 @@ function InternalTable<RecordType extends object = any>(
/>
{bottomPaginationNode}
</Spin>
</div>
</div>,
);
}

View File

@ -185,7 +185,7 @@ describe('Table', () => {
dataSource={[]}
/>,
);
wrapper.simulate('touchmove');
wrapper.find('.ant-table-wrapper').simulate('touchmove');
});
it('renders ellipsis by showTitle option', () => {

View File

@ -294,7 +294,7 @@ export default App;
<style>
.components-table-demo-control-bar .ant-form-item {
margin-right: 16px;
margin-bottom: 8px;
margin-right: 16px !important;
margin-bottom: 8px !important;
}
</style>

View File

@ -1,31 +1,31 @@
import * as React from 'react';
import FilterFilled from '@ant-design/icons/FilterFilled';
import classNames from 'classnames';
import isEqual from 'lodash/isEqual';
import FilterFilled from '@ant-design/icons/FilterFilled';
import Button from '../../../button';
import Menu from '../../../menu';
import type { MenuProps } from '../../../menu';
import Tree from '../../../tree';
import type { DataNode, EventDataNode } from '../../../tree';
import Checkbox from '../../../checkbox';
import type { CheckboxChangeEvent } from '../../../checkbox';
import Radio from '../../../radio';
import Dropdown from '../../../dropdown';
import Empty from '../../../empty';
import type {
ColumnType,
ColumnFilterItem,
Key,
TableLocale,
GetPopupContainer,
FilterSearchType,
} from '../../interface';
import FilterDropdownMenuWrapper from './FilterWrapper';
import FilterSearch from './FilterSearch';
import * as React from 'react';
import type { FilterState } from '.';
import { flattenKeys } from '.';
import useSyncState from '../../../_util/hooks/useSyncState';
import Button from '../../../button';
import type { CheckboxChangeEvent } from '../../../checkbox';
import Checkbox from '../../../checkbox';
import { ConfigContext } from '../../../config-provider/context';
import Dropdown from '../../../dropdown';
import Empty from '../../../empty';
import type { MenuProps } from '../../../menu';
import Menu from '../../../menu';
import Radio from '../../../radio';
import type { DataNode, EventDataNode } from '../../../tree';
import Tree from '../../../tree';
import useSyncState from '../../../_util/hooks/useSyncState';
import type {
ColumnFilterItem,
ColumnType,
FilterSearchType,
GetPopupContainer,
Key,
TableLocale,
} from '../../interface';
import FilterSearch from './FilterSearch';
import FilterDropdownMenuWrapper from './FilterWrapper';
interface FilterRestProps {
confirm?: Boolean;

View File

@ -0,0 +1,159 @@
import type { CSSObject } from '@ant-design/cssinjs';
import type { GenerateStyle } from '../../_util/theme';
import type { TableToken } from './index';
const genBorderedStyle: GenerateStyle<TableToken, CSSObject> = token => {
const { componentCls } = token;
const tableBorder = `${token.controlLineWidth}px ${token.controlLineType} ${token.tableBorderColor}`;
const getSizeBorderStyle = (
size: 'small' | 'middle',
paddingVertical: number,
paddingHorizontal: number,
) => ({
[`&${componentCls}-${size}`]: {
[`> ${componentCls}-container`]: {
[`> ${componentCls}-content, > ${componentCls}-body`]: {
'> table > tbody > tr > td': {
[`> ${componentCls}-expanded-row-fixed`]: {
margin: `-${paddingVertical}px -${paddingHorizontal + token.controlLineWidth}px`,
},
},
},
},
},
});
return {
[`${componentCls}-wrapper`]: {
[`${componentCls}${componentCls}-bordered`]: {
// ============================ Title =============================
[`> ${componentCls}-title`]: {
border: tableBorder,
borderBottom: 0,
},
// ============================ Content ============================
[`> ${componentCls}-container`]: {
borderInlineStart: tableBorder,
[`
> ${componentCls}-content,
> ${componentCls}-header,
> ${componentCls}-body,
> ${componentCls}-summary
`]: {
'> table': {
// ============================= Cell =============================
[`
> thead > tr > th,
> tbody > tr > td,
> tfoot > tr > th,
> tfoot > tr > td
`]: {
borderInlineEnd: tableBorder,
},
// ============================ Header ============================
'> thead': {
'> tr:not(:last-child) > th': {
borderBottom: tableBorder,
},
'> tr > th::before': {
backgroundColor: 'transparent !important',
},
},
// Fixed right should provides additional border
[`
> thead > tr,
> tbody > tr,
> tfoot > tr
`]: {
[`> ${componentCls}-cell-fix-right-first::after`]: {
borderInlineEnd: tableBorder,
},
},
// ========================== Expandable ==========================
'> table > tbody > tr > td': {
[`> ${componentCls}-expanded-row-fixed`]: {
margin: `-${token.tablePaddingVertical}px -${
token.tablePaddingHorizontal + token.controlLineWidth
}px`,
'&::after': {
position: 'absolute',
top: 0,
insetInlineEnd: token.controlLineWidth,
bottom: 0,
borderInlineEnd: tableBorder,
content: '""',
},
},
},
},
},
[`
> ${componentCls}-content,
> ${componentCls}-header
`]: {
'> table': {
borderTop: tableBorder,
},
},
},
// ============================ Scroll ============================
[`&${componentCls}-scroll-horizontal`]: {
[`> ${componentCls}-container > ${componentCls}-body`]: {
'> table > tbody': {
[`
> tr${componentCls}-expanded-row,
> tr${componentCls}-placeholder
`]: {
'> td': {
borderInlineEnd: 0,
},
},
},
},
},
// ============================ Size ============================
...getSizeBorderStyle(
'middle',
token.tablePaddingVerticalMiddle,
token.tablePaddingHorizontalMiddle,
),
...getSizeBorderStyle(
'small',
token.tablePaddingVerticalSmall,
token.tablePaddingHorizontalSmall,
),
// ============================ Footer ============================
[`> ${componentCls}-footer`]: {
border: tableBorder,
borderTop: 0,
},
},
// ============================ Nested ============================
[`${componentCls}-cell`]: {
[`${componentCls}-container:first-child`]: {
// :first-child to avoid the case when bordered and title is set
borderTop: 0,
},
// https://github.com/ant-design/ant-design/issues/35577
'&-scrollbar:not([rowspan])': {
boxShadow: `0 ${token.controlLineWidth}px 0 ${token.controlLineWidth}px ${token.tableHeaderBg}`,
},
},
},
};
};
export default genBorderedStyle;

View File

@ -0,0 +1,38 @@
import type { CSSObject } from '@ant-design/cssinjs';
import type { GenerateStyle } from '../../_util/theme';
import type { TableToken } from './index';
const genEllipsisStyle: GenerateStyle<TableToken, CSSObject> = token => {
const { componentCls } = token;
return {
[`${componentCls}-wrapper`]: {
[`${componentCls}-cell-ellipsis`]: {
overflow: 'hidden',
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
wordBreak: 'keep-all',
// Fixed first or last should special process
[`
&${componentCls}-cell-fix-left-last,
&${componentCls}-cell-fix-right-first
`]: {
overflow: 'visible',
[`${componentCls}-cell-content`]: {
display: 'block',
overflow: 'hidden',
textOverflow: 'ellipsis',
},
},
[`${componentCls}-column-title`]: {
overflow: 'hidden',
textOverflow: 'ellipsis',
wordBreak: 'keep-all',
},
},
},
};
};
export default genEllipsisStyle;

View File

@ -0,0 +1,22 @@
import type { CSSObject } from '@ant-design/cssinjs';
import type { GenerateStyle } from '../../_util/theme';
import type { TableToken } from './index';
// ========================= Placeholder ==========================
const genEmptyStyle: GenerateStyle<TableToken, CSSObject> = token => {
const { componentCls } = token;
return {
[`${componentCls}-wrapper`]: {
[`${componentCls}-tbody > tr${componentCls}-placeholder`]: {
textAlign: 'center',
color: token.colorTextDisabled,
'&:hover > td': {
background: token.colorBgComponent,
},
},
},
};
};
export default genEmptyStyle;

View File

@ -0,0 +1,126 @@
import type { CSSObject } from '@ant-design/cssinjs';
import type { GenerateStyle } from '../../_util/theme';
import { operationUnit } from '../../_util/theme';
import type { TableToken } from './index';
const genExpandStyle: GenerateStyle<TableToken, CSSObject> = token => {
const { componentCls, antCls } = token;
// FIXME: 需要从 checkbox 那里取
const checkboxSize = token.controlInteractiveSize;
const halfInnerSize = checkboxSize / 2 - 1;
// must be odd number, unless it cannot align centerly
const expandIconSize = halfInnerSize * 2 + token.controlLineWidth * 3;
const tableBorder = `${token.controlLineWidth}px ${token.controlLineType} ${token.tableBorderColor}`;
return {
[`${componentCls}-wrapper`]: {
[`${componentCls}-expand-icon-col`]: {
// FIXME
width: 48,
},
[`${componentCls}-row-expand-icon-cell`]: {
textAlign: 'center',
},
[`${componentCls}-row-indent`]: {
height: 1,
},
[`${componentCls}-row-expand-icon`]: {
...operationUnit(token),
position: 'relative',
display: 'inline-flex',
verticalAlign: 'text-top',
boxSizing: 'border-box',
width: expandIconSize,
height: expandIconSize,
padding: 0,
color: 'inherit',
lineHeight: `${expandIconSize}px`,
background: token.tableExpandIconBg,
border: tableBorder,
borderRadius: token.radiusBase,
outline: 'none',
transform: `scale(${checkboxSize / expandIconSize})`,
transition: `all ${token.motionDurationSlow}`,
userSelect: 'none',
[`&:focus, &:hover, &:active`]: {
borderColor: 'currentcolor',
},
[`&::before, &::after`]: {
position: 'absolute',
background: 'currentcolor',
transition: `transform ${token.motionDurationSlow} ease-out`,
content: '""',
},
'&::before': {
top: halfInnerSize,
insetInlineEnd: 3,
insetInlineStart: 3,
height: token.controlLineWidth,
},
'&::after': {
top: 3,
bottom: 3,
insetInlineStart: halfInnerSize,
width: token.controlLineWidth,
transform: 'rotate(90deg)',
},
// Motion effect
'&-collapsed::before': {
transform: 'rotate(-180deg)',
},
'&-collapsed::after': {
transform: 'rotate(0deg)',
},
'&-spaced': {
'&::before, &::after': {
display: 'none',
content: 'none',
},
background: 'transparent',
border: 0,
visibility: 'hidden',
},
},
[`${componentCls}-row-indent + ${componentCls}-row-expand-icon`]: {
marginInlineEnd: token.paddingXS,
},
[`tr${componentCls}-expanded-row`]: {
'&, &:hover': {
'> td': {
background: token.tableExpandedRowBg,
},
},
// https://github.com/ant-design/ant-design/issues/25573
[`${antCls}-descriptions-view`]: {
display: 'flex',
table: {
flex: 'auto',
width: 'auto',
},
},
},
// With fixed
[`${componentCls}-expanded-row-fixed`]: {
position: 'relative',
margin: `-${token.tablePaddingVertical}px -${token.tablePaddingHorizontal}px`,
padding: `${token.tablePaddingVertical}px ${token.tablePaddingHorizontal}px`,
},
},
};
};
export default genExpandStyle;

View File

@ -0,0 +1,148 @@
import type { CSSInterpolation } from '@ant-design/cssinjs';
import type { GenerateStyle } from '../../_util/theme';
import { resetComponent } from '../../_util/theme';
import type { TableToken } from './index';
const genFilterStyle: GenerateStyle<TableToken, CSSInterpolation> = token => {
const { componentCls, antCls, iconCls } = token;
const dropdownPrefixCls = `${antCls}-dropdown`;
const tableFilterDropdownPrefixCls = `${componentCls}-filter-dropdown`;
const treePrefixCls = `${antCls}-tree`;
const tableBorder = `${token.controlLineWidth}px ${token.controlLineType} ${token.tableBorderColor}`;
return [
{
[`${componentCls}-wrapper`]: {
[`${componentCls}-filter-column`]: {
display: 'flex',
justifyContent: 'space-between',
},
[`${componentCls}-filter-trigger`]: {
position: 'relative',
display: 'flex',
alignItems: 'center',
marginBlock: -token.paddingXXS,
marginInline: `${token.paddingXXS}px ${-token.tablePaddingHorizontal / 2}px`,
padding: `0 ${token.paddingXXS}px`,
color: token.tableHeaderIconColor,
fontSize: token.fontSizeSM,
borderRadius: token.radiusBase,
cursor: 'pointer',
transition: `all ${token.motionDurationSlow}`,
'&:hover': {
color: token.colorTextSecondary,
background: token.tableHeaderFilterActiveBg,
},
'&.active': {
color: token.colorPrimary,
},
},
},
},
{
// Dropdown
[`${antCls}-dropdown`]: {
[tableFilterDropdownPrefixCls]: {
...resetComponent(token),
// FIXME
minWidth: 120,
backgroundColor: token.tableFilterDropdownBg,
borderRadius: token.radiusBase,
boxShadow: token.boxShadow,
// Reset menu
[`${dropdownPrefixCls}-menu`]: {
// https://github.com/ant-design/ant-design/issues/4916
// https://github.com/ant-design/ant-design/issues/19542
maxHeight: token.tableFilterDropdownMaxHeight,
overflowX: 'hidden',
border: 0,
boxShadow: 'none',
'&:empty::after': {
display: 'block',
padding: `${token.paddingXS}px 0`,
color: token.colorTextDisabled,
fontSize: token.fontSizeSM,
textAlign: 'center',
content: '"Not Found"',
},
},
[`${tableFilterDropdownPrefixCls}-tree`]: {
paddingBlock: `${token.paddingXS}px 0`,
paddingInline: token.paddingXS,
[treePrefixCls]: {
padding: 0,
},
[`${treePrefixCls}-treenode ${treePrefixCls}-node-content-wrapper:hover`]: {
backgroundColor: token.controlItemBgHover,
},
[`${treePrefixCls}-treenode-checkbox-checked ${treePrefixCls}-node-content-wrapper`]: {
'&, &:hover': {
backgroundColor: token.colorPrimaryActive,
},
},
},
[`${tableFilterDropdownPrefixCls}-search`]: {
padding: token.paddingXS,
borderBottom: tableBorder,
'&-input': {
input: {
// FIXME
minWidth: 140,
},
[iconCls]: {
color: token.colorTextDisabled,
},
},
},
[`${tableFilterDropdownPrefixCls}-checkall`]: {
width: '100%',
marginBottom: token.paddingXXS,
marginInlineStart: token.paddingXXS,
},
// Operation
[`${tableFilterDropdownPrefixCls}-btns`]: {
display: 'flex',
justifyContent: 'space-between',
padding: `${token.paddingXS - 1}px ${token.paddingXS}px`,
overflow: 'hidden',
backgroundColor: 'inherit',
borderTop: tableBorder,
},
},
},
},
// Dropdown Menu & SubMenu
{
// submenu of table filter dropdown
[`${antCls}-dropdown ${tableFilterDropdownPrefixCls}, ${tableFilterDropdownPrefixCls}-submenu`]:
{
// Checkbox
[`${antCls}-checkbox-wrapper + span`]: {
paddingInlineStart: token.paddingXS,
color: token.colorText,
},
[`> ul`]: {
maxHeight: 'calc(100vh - 130px)',
overflowX: 'hidden',
overflowY: 'auto',
},
},
},
];
};
export default genFilterStyle;

View File

@ -0,0 +1,119 @@
import type { CSSObject } from '@ant-design/cssinjs';
import { TinyColor } from '@ctrl/tinycolor';
import type { GenerateStyle } from '../../_util/theme';
import type { TableToken } from './index';
const genFixedStyle: GenerateStyle<TableToken, CSSObject> = token => {
const { componentCls } = token;
// FIXME
const shadowColor = new TinyColor('rgba(0, 0, 0, 0.15)').darken(5).toRgbString();
return {
[`${componentCls}-wrapper`]: {
[`
${componentCls}-cell-fix-left,
${componentCls}-cell-fix-right
`]: {
position: 'sticky !important' as 'sticky',
zIndex: token.zIndexTableFixed,
background: token.tableBg,
},
[`
${componentCls}-cell-fix-left-first::after,
${componentCls}-cell-fix-left-last::after
`]: {
position: 'absolute',
top: 0,
right: {
_skip_check_: true,
value: 0,
},
bottom: -1,
width: 30,
transform: 'translateX(100%)',
transition: `box-shadow ${token.motionDurationSlow}`,
content: '""',
pointerEvents: 'none',
},
[`
${componentCls}-cell-fix-right-first::after,
${componentCls}-cell-fix-right-last::after
`]: {
position: 'absolute',
top: 0,
bottom: -1,
left: {
_skip_check_: true,
value: 0,
},
width: 30,
transform: 'translateX(-100%)',
transition: `box-shadow ${token.motionDurationSlow}`,
content: '""',
pointerEvents: 'none',
},
[`${componentCls}-container`]: {
'&::before, &::after': {
position: 'absolute',
top: 0,
bottom: 0,
zIndex: 1,
width: 30,
transition: `box-shadow ${token.motionDurationSlow}`,
content: '""',
pointerEvents: 'none',
},
'&::before': {
insetInlineStart: 0,
},
'&::after': {
insetInlineEnd: 0,
},
},
[`${componentCls}-ping-left`]: {
[`&:not(${componentCls}-has-fix-left) ${componentCls}-container`]: {
position: 'relative',
'&::before': {
boxShadow: `inset 10px 0 8px -8px ${shadowColor}`,
},
},
[`
${componentCls}-cell-fix-left-first::after,
${componentCls}-cell-fix-left-last::after
`]: {
boxShadow: `inset 10px 0 8px -8px ${shadowColor}`,
},
[`${componentCls}-cell-fix-left-last::before`]: {
backgroundColor: 'transparent !important',
},
},
[`${componentCls}-ping-right`]: {
[`&:not(${componentCls}-has-fix-right) ${componentCls}-container`]: {
position: 'relative',
'&::after': {
boxShadow: `inset -10px 0 8px -8px ${shadowColor}`,
},
},
[`
${componentCls}-cell-fix-right-first::after,
${componentCls}-cell-fix-right-last::after
`]: {
boxShadow: `inset -10px 0 8px -8px ${shadowColor}`,
},
},
},
};
};
export default genFixedStyle;

File diff suppressed because it is too large Load Diff

View File

@ -1,16 +1,258 @@
import '../../style/index.less';
import './index.less';
// deps-lint-skip-all
import type { CSSObject } from '@ant-design/cssinjs';
import { TinyColor } from '@ctrl/tinycolor';
import type { FullToken, GenerateStyle } from '../../_util/theme';
import { clearFix, genComponentStyleHook, mergeToken, resetComponent } from '../../_util/theme';
import genBorderedStyle from './bordered';
import genEllipsisStyle from './ellipsis';
import genEmptyStyle from './empty';
import genExpandStyle from './expand';
import genFilterStyle from './filter';
import genFixedStyle from './fixed';
import genPagniationStyle from './pagination';
import genRadiusStyle from './radius';
import genRtlStyle from './rtl';
import genSelectionStyle from './selection';
import genSizeStyle from './size';
import genSorterStyle from './sorter';
import genStickyStyle from './sticky';
import genSummaryStyle from './summary';
// style dependencies
// deps-lint-skip: menu
// deps-lint-skip: grid
import '../../button/style';
import '../../empty/style';
import '../../radio/style';
import '../../checkbox/style';
import '../../dropdown/style';
import '../../spin/style';
import '../../pagination/style';
import '../../tooltip/style';
import '../../input/style';
import '../../tree/style';
export interface TableToken extends FullToken<'Table'> {
tableFontSize: number;
tableBg: string;
tableRadius: number;
tablePaddingHorizontal: number;
tablePaddingVertical: number;
tablePaddingHorizontalMiddle: number;
tablePaddingVerticalMiddle: number;
tablePaddingHorizontalSmall: number;
tablePaddingVerticalSmall: number;
tableBorderColor: string;
tableHeaderTextColor: string;
tableHeaderBg: string;
tableFooterTextColor: string;
tableFooterBg: string;
tableHeaderCellSplitColor: string;
tableHeaderSortBg: string;
tableHeaderSortHoverBg: string;
tableHeaderIconColor: string;
tableBodySortBg: string;
tableFixedHeaderSortActiveBg: string;
tableHeaderFilterActiveBg: string;
tableFilterDropdownBg: string;
tableFilterDropdownMaxHeight: number;
tableRowHoverBg: string;
tableSelectedRowBg: string;
tableSelectedRowHoverBg: string;
// FIXME: zIndexXxxx 统一提到一个地方
zIndexTableFixed: number;
zIndexTableSticky: number;
tabelFontSizeMiddle: number;
tabelFontSizeSmall: number;
tableSelectionColumnWidth: number;
tableExpandIconBg: string;
tableExpandedRowBg: string;
}
const genTableStyle: GenerateStyle<TableToken, CSSObject> = token => {
const { componentCls } = token;
const tableBorder = `${token.controlLineWidth}px ${token.controlLineType} ${token.tableBorderColor}`;
return {
[`${componentCls}-wrapper`]: {
clear: 'both',
maxWidth: '100%',
...clearFix(),
[componentCls]: {
...resetComponent(token),
fontSize: token.tableFontSize,
background: token.tableBg,
borderRadius: token.tableRadius,
},
// https://github.com/ant-design/ant-design/issues/17611
table: {
width: '100%',
textAlign: 'start',
borderRadius: `${token.tableRadius}px ${token.tableRadius}px 0 0`,
borderCollapse: 'separate',
borderSpacing: 0,
},
// ============================= Cell =============================
[`
${componentCls}-thead > tr > th,
${componentCls}-tbody > tr > td,
tfoot > tr > th,
tfoot > tr > td
`]: {
position: 'relative',
padding: `${token.tablePaddingVertical}px ${token.tablePaddingHorizontal}px`,
overflowWrap: 'break-word',
},
// ============================ Title =============================
[`${componentCls}-title`]: {
padding: `${token.tablePaddingVertical}px ${token.tablePaddingHorizontal}px`,
},
// ============================ Header ============================
[`${componentCls}-thead`]: {
'> tr > th': {
position: 'relative',
color: token.tableHeaderTextColor,
fontWeight: 500,
textAlign: 'start',
background: token.tableHeaderBg,
borderBottom: tableBorder,
transition: `background ${token.motionDurationSlow} ease`,
"&[colspan]:not([colspan='1'])": {
textAlign: 'center',
},
[`&:not(:last-child):not(${componentCls}-selection-column):not(${componentCls}-row-expand-icon-cell):not([colspan])::before`]:
{
position: 'absolute',
top: '50%',
insetInlineEnd: 0,
width: 1,
height: '1.6em',
backgroundColor: token.tableHeaderCellSplitColor,
transform: 'translateY(-50%)',
transition: `background-color ${token.motionDurationSlow}`,
content: '""',
},
},
'> tr:not(:last-child) > th[colspan]': {
borderBottom: 0,
},
},
// ============================ Body ============================
[`${componentCls}-tbody`]: {
'> tr': {
'> td': {
borderBottom: tableBorder,
transition: `background ${token.motionDurationSlow}`,
// ========================= Nest Table ===========================
[`
> ${componentCls}-wrapper:only-child,
> ${componentCls}-expanded-row-fixed > ${componentCls}-wrapper:only-child
`]: {
[componentCls]: {
marginBlock: `-${token.tablePaddingVertical}px`,
marginInline: `${
token.tablePaddingHorizontal + Math.ceil(token.fontSizeSM * 1.4)
}px -${token.tablePaddingHorizontal}px`,
[`${componentCls}-tbody > tr:last-child > td`]: {
borderBottom: 0,
'&:first-child, &:last-child': {
borderRadius: 0,
},
},
},
},
},
[`
&${componentCls}-row:hover > td,
> td${componentCls}-cell-row-hover
`]: {
background: token.tableRowHoverBg,
},
[`&${componentCls}-row-selected`]: {
'> td': {
background: token.tableSelectedRowBg,
// FIXME
borderColor: 'rgba(0, 0, 0, 0.03)',
},
'&:hover > td': {
background: token.tableSelectedRowHoverBg,
},
},
},
},
// ============================ Footer ============================
[`${componentCls}-footer`]: {
padding: `${token.tablePaddingVertical}px ${token.tablePaddingHorizontal}px`,
color: token.tableFooterTextColor,
background: token.tableFooterBg,
},
},
};
};
// ============================== Export ==============================
export default genComponentStyleHook('Table', token => {
// FIXME: missing tokens
const tableSelectedRowBg = token.controlItemBgActive;
const zIndexTableFixed: number = 2;
const tableToken = mergeToken<TableToken>(token, {
tableFontSize: token.fontSizeBase,
tableBg: token.colorBgComponent,
tableRadius: token.radiusBase,
/*
@table-padding-vertical: 16px;
@table-padding-horizontal: 16px;
@table-padding-vertical-md: (@table-padding-vertical * 3 / 4);
@table-padding-horizontal-md: (@table-padding-horizontal / 2);
@table-padding-vertical-sm: (@table-padding-vertical / 2);
@table-padding-horizontal-sm: (@table-padding-horizontal / 2);
*/
tablePaddingVertical: token.padding,
tablePaddingHorizontal: token.padding,
tablePaddingVerticalMiddle: (token.padding * 3) / 4,
tablePaddingHorizontalMiddle: token.padding / 2,
tablePaddingVerticalSmall: token.padding / 2,
tablePaddingHorizontalSmall: token.padding / 2,
tableBorderColor: token.colorSplit,
tableHeaderTextColor: token.colorTextHeading,
tableHeaderBg: token.colorBgComponentSecondary,
tableFooterTextColor: token.colorTextHeading,
tableFooterBg: token.colorBgComponentSecondary,
tableHeaderCellSplitColor: 'rgba(0, 0, 0, 0.06)',
tableHeaderSortBg: token.colorBgContainer,
tableHeaderSortHoverBg: 'rgba(0, 0, 0, 0.04)',
tableHeaderIconColor: '#bfbfbf',
tableBodySortBg: '#fafafa',
tableFixedHeaderSortActiveBg: 'hsv(0, 0, 96%)',
tableHeaderFilterActiveBg: 'rgba(0, 0, 0, 0.04)',
tableFilterDropdownBg: token.colorBgComponent,
tableFilterDropdownMaxHeight: 264,
tableRowHoverBg: token.colorBgComponentSecondary,
tableSelectedRowBg,
tableSelectedRowHoverBg: new TinyColor(tableSelectedRowBg).darken(2).toHexString(),
zIndexTableFixed,
zIndexTableSticky: zIndexTableFixed + 1,
tabelFontSizeMiddle: token.fontSizeBase,
tabelFontSizeSmall: token.fontSizeBase,
tableSelectionColumnWidth: 32,
tableExpandIconBg: token.colorBgComponent,
tableExpandedRowBg: token.colorBgComponentSecondary,
});
return [
genTableStyle(tableToken),
genPagniationStyle(tableToken),
genSummaryStyle(tableToken),
genSorterStyle(tableToken),
genFilterStyle(tableToken),
genBorderedStyle(tableToken),
genRadiusStyle(tableToken),
genExpandStyle(tableToken),
genSummaryStyle(tableToken),
genEmptyStyle(tableToken),
genSelectionStyle(tableToken),
genFixedStyle(tableToken),
genStickyStyle(tableToken),
genEllipsisStyle(tableToken),
genSizeStyle(tableToken),
genRtlStyle(tableToken),
];
});

View File

@ -0,0 +1,39 @@
import type { CSSObject } from '@ant-design/cssinjs';
import type { GenerateStyle } from '../../_util/theme';
import type { TableToken } from './index';
const genPaginationStyle: GenerateStyle<TableToken, CSSObject> = token => {
const { componentCls, antCls } = token;
return {
[`${componentCls}-wrapper`]: {
// ========================== Pagination ==========================
[`${componentCls}-pagination${antCls}-pagination`]: {
margin: `${token.margin}px 0`,
},
[`${componentCls}-pagination`]: {
display: 'flex',
flexWrap: 'wrap',
rowGap: token.paddingXS,
'> *': {
flex: 'none',
},
'&-left': {
justifyContent: 'flex-start',
},
'&-center': {
justifyContent: 'center',
},
'&-right': {
justifyContent: 'flex-end',
},
},
},
};
};
export default genPaginationStyle;

View File

@ -0,0 +1,52 @@
import type { CSSObject } from '@ant-design/cssinjs';
import type { GenerateStyle } from '../../_util/theme';
import type { TableToken } from './index';
const genRadiusStyle: GenerateStyle<TableToken, CSSObject> = token => {
const { componentCls } = token;
return {
[`${componentCls}-wrapper`]: {
[componentCls]: {
'&-title': {
borderRadius: `${token.tableRadius}px ${token.tableRadius}px 0 0`,
},
'&-title + &-container': {
borderStartStartRadius: 0,
borderStartEndRadius: 0,
'table > thead > tr:first-child': {
'th:first-child': {
borderRadius: 0,
},
'th:last-child': {
borderRadius: 0,
},
},
},
'&-container': {
borderStartStartRadius: token.tableRadius,
borderStartEndRadius: token.tableRadius,
'table > thead > tr:first-child': {
'th:first-child': {
borderStartStartRadius: token.tableRadius,
},
'th:last-child': {
borderStartEndRadius: token.tableRadius,
},
},
},
'&-footer': {
borderRadius: `0 0 ${token.tableRadius}px ${token.tableRadius}px`,
},
},
},
};
};
export default genRadiusStyle;

View File

@ -0,0 +1,39 @@
import type { CSSObject } from '@ant-design/cssinjs';
import type { GenerateStyle } from '../../_util/theme';
import type { TableToken } from './index';
const genStyle: GenerateStyle<TableToken, CSSObject> = token => {
const { componentCls } = token;
return {
[`${componentCls}-wrapper-rtl`]: {
direction: 'rtl',
table: {
direction: 'rtl',
},
[`${componentCls}-pagination-left`]: {
justifyContent: 'flex-end',
},
[`${componentCls}-pagination-right`]: {
justifyContent: 'flex-start',
},
[`${componentCls}-row-expand-icon`]: {
'&::after': {
transform: 'rotate(-90deg)',
},
'&-collapsed::before': {
transform: 'rotate(180deg)',
},
'&-collapsed::after': {
transform: 'rotate(0deg)',
},
},
},
};
};
export default genStyle;

View File

@ -0,0 +1,70 @@
import type { CSSObject } from '@ant-design/cssinjs';
import { TinyColor } from '@ctrl/tinycolor';
import type { GenerateStyle } from '../../_util/theme';
import type { TableToken } from './index';
const genSelectionStyle: GenerateStyle<TableToken, CSSObject> = token => {
const { componentCls, antCls, iconCls } = token;
return {
[`${componentCls}-wrapper`]: {
// ========================== Selections ==========================
[`${componentCls}-selection-col`]: {
width: token.tableSelectionColumnWidth,
},
[`${componentCls}-bordered ${componentCls}-selection-col`]: {
// FIXME
width: token.tableSelectionColumnWidth + 18,
},
[`
table tr th${componentCls}-selection-column,
table tr td${componentCls}-selection-column
`]: {
paddingInlineEnd: token.paddingXS,
paddingInlineStart: token.paddingXS,
textAlign: 'center',
[`${antCls}-radio-wrapper`]: {
marginInlineEnd: 0,
},
},
[`table tr th${componentCls}-selection-column${componentCls}-cell-fix-left`]: {
zIndex: token.zIndexTableFixed,
},
[`table tr th${componentCls}-selection-column::after`]: {
backgroundColor: 'transparent !important',
},
[`${componentCls}-selection`]: {
position: 'relative',
display: 'inline-flex',
flexDirection: 'column',
},
[`${componentCls}-selection-extra`]: {
position: 'absolute',
top: 0,
zIndex: 1,
cursor: 'pointer',
transition: `all ${token.motionDurationSlow}`,
marginInlineStart: '100%',
paddingInlineStart: `${token.tablePaddingHorizontal / 4}px`,
[iconCls]: {
color: token.tableHeaderIconColor,
fontSize: 10,
verticalAlign: 'baseline',
'&:hover': {
color: new TinyColor(token.tableHeaderIconColor).darken(10).toRgbString(),
},
},
},
},
};
};
export default genSelectionStyle;

View File

@ -0,0 +1,68 @@
import type { CSSObject } from '@ant-design/cssinjs';
import type { GenerateStyle } from '../../_util/theme';
import type { TableToken } from './index';
const genSizeStyle: GenerateStyle<TableToken, CSSObject> = token => {
const { componentCls } = token;
const getSizeStyle = (
size: 'small' | 'middle',
paddingVertical: number,
paddingHorizontal: number,
fontSize: number,
) => ({
[`${componentCls}${componentCls}-${size}`]: {
fontSize,
[`
${componentCls}-title,
${componentCls}-footer,
${componentCls}-thead > tr > th,
${componentCls}-tbody > tr > td,
tfoot > tr > th,
tfoot > tr > td
`]: {
padding: `${paddingVertical}px ${paddingHorizontal}px`,
},
[`${componentCls}-filter-trigger`]: {
marginInlineEnd: `-${paddingHorizontal / 2}px`,
},
[`${componentCls}-expanded-row-fixed`]: {
margin: `-${paddingVertical}px -${paddingHorizontal}px`,
},
[`${componentCls}-tbody`]: {
// ========================= Nest Table ===========================
[`${componentCls}-wrapper:only-child ${componentCls}`]: {
marginBlock: `-${paddingVertical}px`,
marginInline: `${
paddingHorizontal + Math.ceil(token.fontSizeSM * 1.4)
}px -${paddingHorizontal}px`,
},
},
// https://github.com/ant-design/ant-design/issues/35167
[`${componentCls}-selection-column`]: {
paddingInlineStart: `${paddingHorizontal / 4}px`,
},
},
});
return {
[`${componentCls}-wrapper`]: {
...getSizeStyle(
'middle',
token.tablePaddingVerticalMiddle,
token.tablePaddingHorizontalMiddle,
token.tabelFontSizeMiddle,
),
...getSizeStyle(
'small',
token.tablePaddingVerticalSmall,
token.tablePaddingHorizontalSmall,
token.tabelFontSizeSmall,
),
},
};
};
export default genSizeStyle;

View File

@ -0,0 +1,104 @@
import type { CSSObject } from '@ant-design/cssinjs';
import { TinyColor } from '@ctrl/tinycolor';
import type { GenerateStyle } from '../../_util/theme';
import type { TableToken } from './index';
const genSorterStyle: GenerateStyle<TableToken, CSSObject> = token => {
const { componentCls } = token;
return {
[`${componentCls}-wrapper`]: {
[`${componentCls}-thead th${componentCls}-column-has-sorters`]: {
outline: 'none',
cursor: 'pointer',
transition: `all ${token.motionDurationSlow}`,
'&:hover': {
background: token.tableHeaderSortHoverBg,
'&::before': {
backgroundColor: 'transparent !important',
},
},
'&:focus-visible': {
color: token.colorPrimary,
},
// https://github.com/ant-design/ant-design/issues/30969
[`
&${componentCls}-cell-fix-left:hover,
&${componentCls}-cell-fix-right:hover
`]: {
background: token.tableFixedHeaderSortActiveBg,
},
},
[`${componentCls}-thead th${componentCls}-column-sort`]: {
background: token.tableHeaderSortBg,
'&::before': {
backgroundColor: 'transparent !important',
},
},
[`td${componentCls}-column-sort`]: {
background: token.tableBodySortBg,
},
[`${componentCls}-column-title`]: {
position: 'relative',
zIndex: 1,
flex: 1,
},
[`${componentCls}-column-sorters`]: {
display: 'flex',
flex: 'auto',
alignItems: 'center',
justifyContent: 'space-between',
'&::after': {
position: 'absolute',
top: 0,
insetInlineEnd: 0,
bottom: 0,
insetInlineStart: 0,
width: '100%',
height: '100%',
content: '""',
},
},
[`${componentCls}-column-sorter`]: {
marginInlineStart: 4,
color: token.tableHeaderIconColor,
fontSize: 0,
transition: `color ${token.motionDurationSlow}`,
'&-inner': {
display: 'inline-flex',
flexDirection: 'column',
alignItems: 'center',
},
'&-up, &-down': {
fontSize: 11,
'&.active': {
color: token.colorPrimary,
},
},
[`${componentCls}-column-sorter-up + ${componentCls}-column-sorter-down`]: {
marginTop: '-0.3em',
},
},
[`${componentCls}-column-sorters:hover ${componentCls}-column-sorter`]: {
color: new TinyColor(token.tableHeaderIconColor).darken(10).toHexString(),
},
},
};
};
export default genSorterStyle;

View File

@ -0,0 +1,52 @@
import type { CSSObject } from '@ant-design/cssinjs';
import { TinyColor } from '@ctrl/tinycolor';
import type { GenerateStyle } from '../../_util/theme';
import type { TableToken } from './index';
const genStickyStyle: GenerateStyle<TableToken, CSSObject> = token => {
const { componentCls } = token;
const tableBorder = `${token.controlLineWidth}px ${token.controlLineType} ${token.tableBorderColor}`;
return {
[`${componentCls}-wrapper`]: {
[`${componentCls}-sticky`]: {
'&-holder': {
position: 'sticky',
zIndex: token.zIndexTableSticky,
background: token.colorBgComponent,
},
'&-scroll': {
position: 'sticky',
bottom: 0,
zIndex: token.zIndexTableSticky,
display: 'flex',
alignItems: 'center',
background: new TinyColor(token.tableBorderColor).lighten(80).toRgbString(),
borderTop: tableBorder,
opacity: 0.6,
'&:hover': {
transformOrigin: 'center bottom',
},
// fake scrollbar style of sticky
'&-bar': {
// FIXME
height: 8,
// FIXME
backgroundColor: 'rgba(0, 0, 0, 0.35)',
borderRadius: 100,
transition: `all ${token.motionDurationSlow}`,
'&:hover, &-active': {
// FIXME
backgroundColor: 'rgba(0, 0, 0, 0.8)',
},
},
},
},
},
};
};
export default genStickyStyle;

View File

@ -0,0 +1,29 @@
import type { CSSObject } from '@ant-design/cssinjs';
import type { GenerateStyle } from '../../_util/theme';
import type { TableToken } from './index';
const genSummaryStyle: GenerateStyle<TableToken, CSSObject> = token => {
const { componentCls } = token;
const tableBorder = `${token.controlLineWidth}px ${token.controlLineType} ${token.tableBorderColor}`;
return {
[`${componentCls}-wrapper`]: {
[`${componentCls}-summary`]: {
position: 'relative',
zIndex: token.zIndexTableFixed,
background: token.tableBg,
'> tr': {
'> th, > td': {
borderBottom: tableBorder,
},
},
},
[`div${componentCls}-summary`]: {
boxShadow: `0 -${token.controlLineWidth}px 0 ${token.tableBorderColor}`,
},
},
};
};
export default genSummaryStyle;