Skip to content

Commit

Permalink
refactor(tree): 重构tree组件 (#878#845)
Browse files Browse the repository at this point in the history
  • Loading branch information
matuancc authored Jul 16, 2022
1 parent 213840b commit 08138b6
Show file tree
Hide file tree
Showing 3 changed files with 219 additions and 15 deletions.
44 changes: 32 additions & 12 deletions packages/react-tree/src/TreeNode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@ import { CSSTransition } from 'react-transition-group';
import Icon, { IconProps } from '@uiw/react-icon';
import { IProps, noop } from '@uiw/utils';
import { TreeData, TreeProps, getChildKeys } from './';
import {
CSSTransitionWarp,
TreeNodeUl,
TreeNodeUlLidiv,
TreeNodeUlLidivSpan,
TreeNodeUlLidivSpanIcon,
TreeNodeUlLidivSpanDiv,
} from './style/index';

interface TreeNodeIconProps {
isOpen: boolean;
Expand All @@ -21,6 +29,7 @@ interface DisabledObj {
interface TreeNodeProps<T = (data: TreeData, props: TreeNodeIconProps) => IconProps['type']> extends IProps {
data: TreeData[];
level: number;
isOpen?: boolean;
parent?: TreeData;
icon?: T;
iconAnimation?: boolean;
Expand Down Expand Up @@ -79,7 +88,8 @@ export default function TreeNode<T>(props: TreeNodeProps<T>) {
}, []);

return (
<CSSTransition
<CSSTransitionWarp
as={CSSTransition}
nodeRef={node}
classNames={prefixCls}
in={isOpen}
Expand All @@ -90,8 +100,10 @@ export default function TreeNode<T>(props: TreeNodeProps<T>) {
onEntered={onEntered}
onEntering={onEntering}
>
<ul
<TreeNodeUl
ref={node}
isOpen={isOpen}
level={level}
className={[
level !== 1 && isOpen ? [`${prefixCls}-open`] : null,
level !== 1 && !isOpen ? [`${prefixCls}-close`] : null,
Expand Down Expand Up @@ -133,14 +145,19 @@ export default function TreeNode<T>(props: TreeNodeProps<T>) {
}
return (
<li key={idx} style={{ display: item.hideNode ? 'none' : 'block' }}>
<div className={`${prefixCls}-label`}>
<span
<TreeNodeUlLidiv className={`${prefixCls}-label`}>
<TreeNodeUlLidivSpan
style={{ display: noChild ? 'none' : 'auto' }}
className={`${prefixCls}-switcher`}
onClick={(evn) => onItemClick(item, evn)}
onClick={(evn: React.MouseEvent<HTMLElement, MouseEvent>) => onItemClick(item, evn)}
>
<Icon
<TreeNodeUlLidivSpanIcon
as={Icon}
type={iconItem || 'caret-right'}
isIcon={typeof icon}
isNoChild={noChild}
isIconAnimation={iconAnimation}
isItemIsOpen={itemIsOpen}
className={[
typeof icon === 'function' ? `${prefixCls}-switcher-noop` : null,
noChild ? 'no-child' : null,
Expand All @@ -151,9 +168,12 @@ export default function TreeNode<T>(props: TreeNodeProps<T>) {
.join(' ')
.trim()}
/>
</span>
<div
</TreeNodeUlLidivSpan>
<TreeNodeUlLidivSpanDiv
onClick={(evn) => disabledObj.onClick?.(item, evn)}
judgeSelected={selected}
judgeisSelected={isSelected}
isDisabled={disabledObj.disabled}
className={[
`${prefixCls}-title`,
selected && isSelected ? 'selected' : null,
Expand All @@ -178,8 +198,8 @@ export default function TreeNode<T>(props: TreeNodeProps<T>) {
) : (
<Label label={item.label} className={disabledObj.disabledClass} />
)}
</div>
</div>
</TreeNodeUlLidivSpanDiv>
</TreeNodeUlLidiv>
{item.children && (
<TreeNode
{...other}
Expand All @@ -203,7 +223,7 @@ export default function TreeNode<T>(props: TreeNodeProps<T>) {
</li>
);
})}
</ul>
</CSSTransition>
</TreeNodeUl>
</CSSTransitionWarp>
);
}
7 changes: 4 additions & 3 deletions packages/react-tree/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import React, { useEffect, useState } from 'react';
import { IconProps } from '@uiw/react-icon';
import { IProps, HTMLDivProps, noop } from '@uiw/utils';
import TreeNode from './TreeNode';
import './style/index.less';
// import './style/index.less';
import { TreeNodeDiv } from './style/index';

export type TreeRenderTitleNode = {
selected?: boolean;
Expand Down Expand Up @@ -219,7 +220,7 @@ export default function Tree(props: TreeProps) {
onChange?.(item.key, selKeys);
}
return (
<div className={cls} {...elementProps}>
<TreeNodeDiv className={cls} {...elementProps}>
<TreeNode
{...{
icon,
Expand All @@ -235,6 +236,6 @@ export default function Tree(props: TreeProps) {
data={data}
level={1}
/>
</div>
</TreeNodeDiv>
);
}
183 changes: 183 additions & 0 deletions packages/react-tree/src/style/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
import styled, { css } from 'styled-components';
import { getThemeVariantValue } from '@uiw/utils';
import { TreeRenderTitleNode, TreeProps } from '../index';

interface CSSTransitionWarpProps extends TreeRenderTitleNode {
defaultTheme?: Record<string, string | number>;
isOpen: boolean;
level: number;
}
interface TreeNodeUlLidivProps {
defaultTheme?: Record<string, string | number>;
}

interface TreeNodeUlLidivSpanIconProps {
defaultTheme?: Record<string, string | number>;
isIcon?: string;
isNoChild?: boolean;
isIconAnimation?: boolean;
isItemIsOpen?: boolean;
}
interface TreeNodeUlLidivSpanDivProps {
judgeSelected?: boolean;
judgeisSelected?: boolean;
isDisabled?: string | null;
}
interface TreeNodeDivProps extends TreeProps {
defaultTheme?: Record<string, string | number>;
}

export const CSSTransitionWarp = styled.div<CSSTransitionWarpProps>`
font-size: ${(props) => getThemeVariantValue(props, 'fontSizeCSSTransitionWarpDefault')};
`;

CSSTransitionWarp.defaultProps = {
defaultTheme: {
fontSizeCSSTransitionWarpDefault: '14px',
},
};

export const TreeNodeUl = styled.ul<CSSTransitionWarpProps>`
padding: 0 !important;
transition: 0.3s all;
overflow: hidden;
margin: 0;
ul {
padding-left: 18px !important;
margin-bottom: 0;
}
li {
list-style: none !important;
& + li {
margin-top: 2px !important;
}
&:first-child {
padding-top: 3px;
}
}
${(props) => props.level !== 1 && props.isOpen && css``}
${(props) =>
props.level !== 1 &&
!props.isOpen &&
css`
height: 0;
`}
`;

export const TreeNodeUlLidiv = styled.div<TreeNodeUlLidivProps>`
line-height: initial;
& > * {
vertical-align: middle;
}
`;

export const TreeNodeUlLidivSpan = styled.div<TreeNodeUlLidivProps>`
cursor: pointer;
position: relative;
z-index: 1;
width: 14px;
height: 14px;
line-height: 14px;
display: inline-block;
text-align: center;
&:hover {
color: ${(props) => getThemeVariantValue(props, 'colorTreeNodeUlLidivSpanDefault')};
}
.w-icon {
transition: 0.3s all;
transform: ${(props) => getThemeVariantValue(props, 'transformTreeNodeUlLidivSpanDefault')};
}
`;

TreeNodeUlLidivSpan.defaultProps = {
defaultTheme: {
colorTreeNodeUlLidivSpanDefault: '#2ea3f4',
transformTreeNodeUlLidivSpanDefault: 'scale(0.79) rotate(0deg)',
},
};

export const TreeNodeUlLidivSpanIcon = styled.div<TreeNodeUlLidivSpanIconProps>`
${(props) =>
props.isNoChild &&
!props.isIcon &&
css`
display: none;
`}
${(props) =>
props.isItemIsOpen &&
props.isIconAnimation &&
css`
transform: ${(props) => getThemeVariantValue(props, 'transformTreeNodeUlLidivSpanIconDefault')};
`}
`;

TreeNodeUlLidivSpanIcon.defaultProps = {
defaultTheme: {
transformTreeNodeUlLidivSpanIconDefault: 'scale(0.79) rotate(90deg) !important;',
},
};

export const TreeNodeUlLidivSpanDiv = styled.div<TreeNodeUlLidivSpanDivProps>`
display: inline-block;
padding: 2px 5px;
cursor: pointer;
${(props) =>
props.judgeSelected &&
props.judgeisSelected &&
css`
background-color: #d5e8fc;
`}
${(props) =>
props.judgeSelected &&
css`
cursor: not-allowed;
`}
> * {
vertical-align: middle;
}
`;

export const TreeNodeDiv = styled.div<TreeNodeDivProps>`
li {
position: relative;
li {
&:before,
&::after {
content: ' ';
border-left: 1px solid #d9d9d9;
left: -12px;
position: absolute;
}
&::after {
height: 100%;
top: 5px;
}
&:last-child::after {
height: 16px;
top: -18px;
}
&:before {
content: ' ';
width: 10px;
height: 16px;
border-bottom: 1px solid #d9d9d9;
top: -2px;
}
&:last-child::before {
border-radius: ${(props) => getThemeVariantValue(props, 'borderRadiusTreeNodeDivDefault')};
}
}
}
`;

TreeNodeDiv.defaultProps = {
defaultTheme: {
borderRadiusTreeNodeDivDefault: '0 0 0 3px;',
},
};

0 comments on commit 08138b6

Please sign in to comment.