feat: tree token (#44282)

This commit is contained in:
MadCcc 2023-08-18 10:23:57 +08:00 committed by GitHub
parent 2e18b63cec
commit 74d9654423
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 286 additions and 52 deletions

View File

@ -54,6 +54,8 @@ import type { ComponentToken as TimelineComponentToken } from '../../timeline/st
import type { ComponentToken as TooltipComponentToken } from '../../tooltip/style';
import type { ComponentToken as TourComponentToken } from '../../tour/style';
import type { ComponentToken as TransferComponentToken } from '../../transfer/style';
import type { ComponentToken as TreeComponentToken } from '../../tree/style';
import type { ComponentToken as TreeSelectComponentToken } from '../../tree-select/style';
import type { ComponentToken as TypographyComponentToken } from '../../typography/style';
import type { ComponentToken as UploadComponentToken } from '../../upload/style';
@ -102,8 +104,8 @@ export interface ComponentTokenMap {
Statistic?: StatisticComponentToken;
Switch?: SwitchComponentToken;
Tag?: TagComponentToken;
Tree?: {};
TreeSelect?: {};
Tree?: TreeComponentToken;
TreeSelect?: TreeSelectComponentToken;
Typography?: TypographyComponentToken;
Timeline?: TimelineComponentToken;
Transfer?: TransferComponentToken;

View File

@ -1,3 +1,3 @@
import { extendTest } from '../../../tests/shared/demoTest';
extendTest('tree-select');
extendTest('tree-select', { skip: ['component-token.tsx'] });

View File

@ -3,6 +3,7 @@ import demoTest, { rootPropsTest } from '../../../tests/shared/demoTest';
demoTest('tree-select', {
testRootProps: false,
skip: ['component-token.tsx'],
});
rootPropsTest('tree-select', (TreeSelect, props) => <TreeSelect {...props} />, {

View File

@ -0,0 +1,7 @@
## zh-CN
组件 Token
## en-US
Component Token

View File

@ -0,0 +1,69 @@
import React, { useState } from 'react';
import { ConfigProvider, TreeSelect } from 'antd';
const treeData = [
{
value: 'parent 1',
title: 'parent 1',
children: [
{
value: 'parent 1-0',
title: 'parent 1-0',
children: [
{
value: 'leaf1',
title: 'leaf1',
},
{
value: 'leaf2',
title: 'leaf2',
},
],
},
{
value: 'parent 1-1',
title: 'parent 1-1',
children: [
{
value: 'leaf3',
title: <b style={{ color: '#08c' }}>leaf3</b>,
},
],
},
],
},
];
const App: React.FC = () => {
const [value, setValue] = useState<string>();
const onChange = (newValue: string) => {
setValue(newValue);
};
return (
<ConfigProvider
theme={{
components: {
TreeSelect: {
nodeHoverBg: '#fff2f0',
nodeSelectedBg: '#ffa39e',
},
},
}}
>
<TreeSelect
showSearch
style={{ width: '100%' }}
value={value}
dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
placeholder="Please select"
allowClear
treeDefaultExpandAll
onChange={onChange}
treeData={treeData}
/>
</ConfigProvider>
);
};
export default App;

View File

@ -27,6 +27,7 @@ Tree selection control.
<code src="./demo/status.tsx">Status</code>
<code src="./demo/suffix.tsx" debug>Suffix</code>
<code src="./demo/render-panel.tsx" debug>_InternalPanelDoNotUseOrYouWillBeFired</code>
<code src="./demo/component-token.tsx" debug>Component Token</code>
## API

View File

@ -28,6 +28,7 @@ demo:
<code src="./demo/status.tsx">自定义状态</code>
<code src="./demo/suffix.tsx" debug>后缀图标</code>
<code src="./demo/render-panel.tsx" debug>\_InternalPanelDoNotUseOrYouWillBeFired</code>
<code src="./demo/component-token.tsx" debug>组件 Token</code>
## API

View File

@ -1,7 +1,10 @@
import { getStyle as getCheckboxStyle } from '../../checkbox/style';
import type { AliasToken, FullToken, GenerateStyle } from '../../theme/internal';
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
import { genTreeStyle } from '../../tree/style';
import type { TreeSharedToken } from '../../tree/style';
import { genTreeStyle, initComponentToken } from '../../tree/style';
export interface ComponentToken extends TreeSharedToken {}
interface TreeSelectToken extends FullToken<'TreeSelect'> {
treePrefixCls: string;
@ -25,7 +28,7 @@ const genBaseStyle: GenerateStyle<TreeSelectToken> = (token) => {
// ====================== Tree ======================
genTreeStyle(
treePrefixCls,
mergeToken<AliasToken>(token, { colorBgContainer: colorBgElevated }),
mergeToken<AliasToken & TreeSharedToken>(token, { colorBgContainer: colorBgElevated }),
),
{
[treeCls]: {
@ -64,8 +67,12 @@ const genBaseStyle: GenerateStyle<TreeSelectToken> = (token) => {
// ============================== Export ==============================
export default function useTreeSelectStyle(prefixCls: string, treePrefixCls: string) {
return genComponentStyleHook('TreeSelect', (token) => {
const treeSelectToken = mergeToken<TreeSelectToken>(token, { treePrefixCls });
return [genBaseStyle(treeSelectToken)];
})(prefixCls);
return genComponentStyleHook(
'TreeSelect',
(token) => {
const treeSelectToken = mergeToken<TreeSelectToken>(token, { treePrefixCls });
return [genBaseStyle(treeSelectToken)];
},
initComponentToken,
)(prefixCls);
}

View File

@ -1,3 +1,3 @@
import { extendTest } from '../../../tests/shared/demoTest';
extendTest('tree', { skip: ['big-data.tsx', 'virtual-scroll.tsx'] });
extendTest('tree', { skip: ['big-data.tsx', 'virtual-scroll.tsx', 'component-token.tsx'] });

View File

@ -1,3 +1,3 @@
import demoTest from '../../../tests/shared/demoTest';
demoTest('tree', { skip: ['big-data.tsx', 'virtual-scroll.tsx'] });
demoTest('tree', { skip: ['big-data.tsx', 'virtual-scroll.tsx', 'component-token.tsx'] });

View File

@ -0,0 +1,7 @@
## zh-CN
组件 Token
## en-US
Component Token

View File

@ -0,0 +1,68 @@
import React from 'react';
import { ConfigProvider, Tree } from 'antd';
import type { DataNode, TreeProps } from 'antd/es/tree';
const treeData: DataNode[] = [
{
title: 'parent 1',
key: '0-0',
children: [
{
title: 'parent 1-0',
key: '0-0-0',
disabled: true,
children: [
{
title: 'leaf',
key: '0-0-0-0',
disableCheckbox: true,
},
{
title: 'leaf',
key: '0-0-0-1',
},
],
},
{
title: 'parent 1-1',
key: '0-0-1',
children: [{ title: <span style={{ color: '#1677ff' }}>sss</span>, key: '0-0-1-0' }],
},
],
},
];
const App: React.FC = () => {
const onSelect: TreeProps['onSelect'] = (selectedKeys, info) => {
console.log('selected', selectedKeys, info);
};
const onCheck: TreeProps['onCheck'] = (checkedKeys, info) => {
console.log('onCheck', checkedKeys, info);
};
return (
<ConfigProvider
theme={{
components: {
Tree: {
nodeHoverBg: '#fff2f0',
nodeSelectedBg: '#ffa39e',
},
},
}}
>
<Tree
checkable
defaultExpandedKeys={['0-0-0', '0-0-1']}
defaultSelectedKeys={['0-0-0', '0-0-1']}
defaultCheckedKeys={['0-0-0', '0-0-1']}
onSelect={onSelect}
onCheck={onCheck}
treeData={treeData}
/>
</ConfigProvider>
);
};
export default App;

View File

@ -30,6 +30,7 @@ Almost anything can be represented in a tree structure. Examples include directo
<code src="./demo/drag-debug.tsx" debug>Drag Debug</code>
<code src="./demo/big-data.tsx" debug>Big data</code>
<code src="./demo/block-node.tsx">Block Node</code>
<code src="./demo/component-token.tsx" debug>Component Token</code>
## API
@ -126,7 +127,7 @@ Before `3.4.0`: The number of treeNodes can be very large, but when `checkable=t
## Design Token
<ComponentTokenTable component="Transfer"></ComponentTokenTable>
<ComponentTokenTable component="Tree"></ComponentTokenTable>
## FAQ

View File

@ -31,6 +31,7 @@ demo:
<code src="./demo/drag-debug.tsx" debug>Drag Debug</code>
<code src="./demo/big-data.tsx" debug>大数据</code>
<code src="./demo/block-node.tsx">占据整行</code>
<code src="./demo/component-token.tsx" debug>组件 Token</code>
## API
@ -128,7 +129,7 @@ demo:
## Design Token
<ComponentTokenTable component="Transfer"></ComponentTokenTable>
<ComponentTokenTable component="Tree"></ComponentTokenTable>
## FAQ

View File

@ -3,9 +3,40 @@ import { Keyframes } from '@ant-design/cssinjs';
import { getStyle as getCheckboxStyle } from '../../checkbox/style';
import { genFocusOutline, resetComponent } from '../../style';
import { genCollapseMotion } from '../../style/motion';
import type { DerivativeToken } from '../../theme/internal';
import type { AliasToken, DerivativeToken, FullToken } from '../../theme/internal';
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
export interface TreeSharedToken {
/**
* @desc
* @descEN Node title height
*/
titleHeight: number;
/**
* @desc
* @descEN Background color of hovered node
*/
nodeHoverBg: string;
/**
* @desc
* @descEN Background color of selected node
*/
nodeSelectedBg: string;
}
export interface ComponentToken extends TreeSharedToken {
/**
* @desc
* @descEN Text color of selected directory node
*/
directoryNodeSelectedColor: string;
/**
* @desc
* @descEN Background color of selected directory node
*/
directoryNodeSelectedBg: string;
}
// ============================ Keyframes =============================
const treeNodeFX = new Keyframes('ant-tree-node-fx-do-not-use', {
'0%': {
@ -55,15 +86,14 @@ const getDropIndicatorStyle = (prefixCls: string, token: DerivativeToken) => ({
});
// =============================== Base ===============================
type TreeToken = DerivativeToken & {
type TreeToken = FullToken<'Tree'> & {
treeCls: string;
treeNodeCls: string;
treeNodePadding: number;
treeTitleHeight: number;
};
export const genBaseStyle = (prefixCls: string, token: TreeToken): CSSObject => {
const { treeCls, treeNodeCls, treeNodePadding, treeTitleHeight } = token;
const { treeCls, treeNodeCls, treeNodePadding, titleHeight, nodeSelectedBg, nodeHoverBg } = token;
const treeCheckBoxMarginHorizontal = token.paddingXS;
return {
@ -163,8 +193,8 @@ export const genBaseStyle = (prefixCls: string, token: TreeToken): CSSObject =>
[`${treeCls}-draggable-icon`]: {
// https://github.com/ant-design/ant-design/issues/41915
flexShrink: 0,
width: treeTitleHeight,
lineHeight: `${treeTitleHeight}px`,
width: titleHeight,
lineHeight: `${titleHeight}px`,
textAlign: 'center',
visibility: 'visible',
opacity: 0.2,
@ -190,7 +220,7 @@ export const genBaseStyle = (prefixCls: string, token: TreeToken): CSSObject =>
userSelect: 'none',
'&-unit': {
display: 'inline-block',
width: treeTitleHeight,
width: titleHeight,
},
},
@ -205,9 +235,9 @@ export const genBaseStyle = (prefixCls: string, token: TreeToken): CSSObject =>
position: 'relative',
flex: 'none',
alignSelf: 'stretch',
width: treeTitleHeight,
width: titleHeight,
margin: 0,
lineHeight: `${treeTitleHeight}px`,
lineHeight: `${titleHeight}px`,
textAlign: 'center',
cursor: 'pointer',
userSelect: 'none',
@ -239,7 +269,7 @@ export const genBaseStyle = (prefixCls: string, token: TreeToken): CSSObject =>
'&:before': {
position: 'absolute',
top: 0,
insetInlineEnd: treeTitleHeight / 2,
insetInlineEnd: titleHeight / 2,
bottom: -treeNodePadding,
marginInlineStart: -1,
borderInlineEnd: `1px solid ${token.colorBorder}`,
@ -248,8 +278,8 @@ export const genBaseStyle = (prefixCls: string, token: TreeToken): CSSObject =>
'&:after': {
position: 'absolute',
width: (treeTitleHeight / 2) * 0.8,
height: treeTitleHeight / 2,
width: (titleHeight / 2) * 0.8,
height: titleHeight / 2,
borderBottom: `1px solid ${token.colorBorder}`,
content: '""',
},
@ -267,30 +297,30 @@ export const genBaseStyle = (prefixCls: string, token: TreeToken): CSSObject =>
[`${treeCls}-node-content-wrapper, ${treeCls}-checkbox + span`]: {
position: 'relative',
zIndex: 'auto',
minHeight: treeTitleHeight,
minHeight: titleHeight,
margin: 0,
padding: `0 ${token.paddingXS / 2}px`,
color: 'inherit',
lineHeight: `${treeTitleHeight}px`,
lineHeight: `${titleHeight}px`,
background: 'transparent',
borderRadius: token.borderRadius,
cursor: 'pointer',
transition: `all ${token.motionDurationMid}, border 0s, line-height 0s, box-shadow 0s`,
'&:hover': {
backgroundColor: token.controlItemBgHover,
backgroundColor: nodeHoverBg,
},
[`&${treeCls}-node-selected`]: {
backgroundColor: token.controlItemBgActive,
backgroundColor: nodeSelectedBg,
},
// Icon
[`${treeCls}-iconEle`]: {
display: 'inline-block',
width: treeTitleHeight,
height: treeTitleHeight,
lineHeight: `${treeTitleHeight}px`,
width: titleHeight,
height: titleHeight,
lineHeight: `${titleHeight}px`,
textAlign: 'center',
verticalAlign: 'top',
@ -307,7 +337,7 @@ export const genBaseStyle = (prefixCls: string, token: TreeToken): CSSObject =>
// ==================== Draggable =====================
[`${treeCls}-node-content-wrapper`]: {
lineHeight: `${treeTitleHeight}px`,
lineHeight: `${titleHeight}px`,
userSelect: 'none',
...getDropIndicatorStyle(prefixCls, token),
@ -330,7 +360,7 @@ export const genBaseStyle = (prefixCls: string, token: TreeToken): CSSObject =>
'&:before': {
position: 'absolute',
top: 0,
insetInlineEnd: treeTitleHeight / 2,
insetInlineEnd: titleHeight / 2,
bottom: -treeNodePadding,
borderInlineEnd: `1px solid ${token.colorBorder}`,
content: '""',
@ -361,7 +391,7 @@ export const genBaseStyle = (prefixCls: string, token: TreeToken): CSSObject =>
'&:before': {
top: 'auto !important',
bottom: 'auto !important',
height: `${treeTitleHeight / 2}px !important`,
height: `${titleHeight / 2}px !important`,
},
},
},
@ -372,7 +402,13 @@ export const genBaseStyle = (prefixCls: string, token: TreeToken): CSSObject =>
// ============================ Directory =============================
export const genDirectoryStyle = (token: TreeToken): CSSObject => {
const { treeCls, treeNodeCls, treeNodePadding } = token;
const {
treeCls,
treeNodeCls,
treeNodePadding,
directoryNodeSelectedBg,
directoryNodeSelectedColor,
} = token;
return {
[`${treeCls}${treeCls}-directory`]: {
@ -418,7 +454,7 @@ export const genDirectoryStyle = (token: TreeToken): CSSObject => {
},
[`&${treeCls}-node-selected`]: {
color: token.colorTextLightSolid,
color: directoryNodeSelectedColor,
background: 'transparent',
},
},
@ -429,17 +465,17 @@ export const genDirectoryStyle = (token: TreeToken): CSSObject => {
&:hover::before,
&::before
`]: {
background: token.colorPrimary,
background: directoryNodeSelectedBg,
},
// >>> Switcher
[`${treeCls}-switcher`]: {
color: token.colorTextLightSolid,
color: directoryNodeSelectedColor,
},
// >>> Title
[`${treeCls}-node-content-wrapper`]: {
color: token.colorTextLightSolid,
color: directoryNodeSelectedColor,
background: 'transparent',
},
},
@ -449,18 +485,19 @@ export const genDirectoryStyle = (token: TreeToken): CSSObject => {
};
// ============================== Merged ==============================
export const genTreeStyle = (prefixCls: string, token: DerivativeToken): CSSInterpolation => {
export const genTreeStyle = (
prefixCls: string,
token: AliasToken & TreeSharedToken,
): CSSInterpolation => {
const treeCls = `.${prefixCls}`;
const treeNodeCls = `${treeCls}-treenode`;
const treeNodePadding = token.paddingXS / 2;
const treeTitleHeight = token.controlHeightSM;
const treeToken = mergeToken<TreeToken>(token, {
treeCls,
treeNodeCls,
treeNodePadding,
treeTitleHeight,
});
return [
@ -471,11 +508,32 @@ export const genTreeStyle = (prefixCls: string, token: DerivativeToken): CSSInte
];
};
// ============================== Export ==============================
export default genComponentStyleHook('Tree', (token, { prefixCls }) => [
{
[token.componentCls]: getCheckboxStyle(`${prefixCls}-checkbox`, token),
export const initComponentToken = (token: AliasToken): TreeSharedToken => {
const { controlHeightSM } = token;
return {
titleHeight: controlHeightSM,
nodeHoverBg: token.controlItemBgHover,
nodeSelectedBg: token.controlItemBgActive,
};
};
export default genComponentStyleHook(
'Tree',
(token, { prefixCls }) => [
{
[token.componentCls]: getCheckboxStyle(`${prefixCls}-checkbox`, token),
},
genTreeStyle(prefixCls, token),
genCollapseMotion(token),
],
(token) => {
const { colorTextLightSolid, colorPrimary } = token;
return {
...initComponentToken(token),
directoryNodeSelectedColor: colorTextLightSolid,
directoryNodeSelectedBg: colorPrimary,
};
},
genTreeStyle(prefixCls, token),
genCollapseMotion(token),
]);
);

View File

@ -797,7 +797,7 @@ Mentions 提及
| `@tooltip-arrow-color` | - | 同 `@tooltip-bg`,已废弃 |
| `@tooltip-border-radius` | `borderRadius` | 全局 Token |
Transfer 穿梭框
### Transfer 穿梭框
<!-- prettier-ignore -->
| Less variables | Component Token | Note |
@ -811,7 +811,18 @@ Transfer 穿梭框
| `@transfer-item-padding-vertical` | `itemPaddingBlock` | - |
| `@transfer-list-search-icon-top` | - | 已废弃 |
<!-- ### Tree 树形控件 -->
### Tree 树形控件
<!-- prettier-ignore -->
| Less 变量 | Component Token | 备注 |
| --- | --- | --- |
| `@tree-bg` | `colorBgContainer` | 全局 Token |
| `@tree-title-height` | `titleHeight` | - |
| `@tree-child-padding` | - | 已废弃 |
| `@tree-directory-selected-color` | `directoryNodeSelectedColor` | - |
| `@tree-directory-selected-bg` | `directoryNodeSelectedBg` | - |
| `@tree-node-hover-bg` | `nodeHoverBg` | - |
| `@tree-node-selected-bg` | `nodeSelectedBg` | - |
### Typography 排版